Компьютерная графика
Deferred Rendering
В 2007 Crysis показал 300 динамических источников света на сцену - и потребовал GeForce 8800 SLI для 30 fps. В 2020 Doom Eternal даёт 2000 источников света при 60 fps на средней RTX 2060. За 13 лет случилась тихая революция в архитектуре rendering pipeline: G-Buffer, tiled, clustered shading изменили, как современные GPU вообще считают свет.
- **Doom Eternal** - clustered forward+ с 2000+ динамических светов на сцене при 60 fps на RTX 2060
- **Unreal Engine 5 Lumen** - гибрид: deferred для opaque + forward для transparent + ray tracing для select reflections
- **Detroit: Become Human** - clustered shading для сцен с десятками источников света в интерьерах
G-Buffer: геометрия на потом
В Crysis (2007) на одну сцену пришлось 300 динамических источников света и 5000 объектов. Классический forward rendering требует прогонять каждый объект через каждый свет: 5000 * 300 = 1.5 миллиона прогонов шейдера на кадр. На GeForce 8800 это 5 fps. **Deferred rendering** перевернул схему: сначала записать геометрические свойства в **G-Buffer**, потом считать освещение per-pixel, независимо от количества объектов.
**G-Buffer (Geometry Buffer)** - набор full-screen render target'ов, в которые geometry pass записывает: world position, normal, albedo, metallic/roughness, emissive. После geometry pass геометрия уже не нужна - все вычисления освещения работают только с G-Buffer как с большим input-изображением. Типичный размер G-Buffer для 1920x1080: 4-5 RT * 4 bytes/channel * 4 channels = ~150 МБ VRAM.
**Packing tricks**: 150 МБ G-Buffer - дорого по bandwidth. Современные движки (Unreal, Frostbite) пакуют данные: normal через octahedron encoding в 2 канала, world position восстанавливают из depth + inverse projection, metallic/roughness в один RG.
Почему G-Buffer избавляет от проблемы 'каждый объект для каждого света'?
Deferred vs Forward
Deferred решает проблему многих источников света, но имеет свои недостатки. **Прозрачность** - принципиальная проблема: G-Buffer хранит один фрагмент на пиксель, а через стекло видна геометрия за ним. Решение: hybrid pipeline - opaque deferred + transparent forward в отдельном pass. **MSAA** в deferred требует огромного G-Buffer (4x sample count), что часто заменяется на TAA/FXAA.
**Forward+** (forward with light culling) - современная альтернатива: классический forward, но с предварительным culling источников света на тайлы/кластеры. На сцене с 100 светами шейдер каждого объекта итерируется только по 8-12 близким светам, а не по всем 100. Сложность падает с O(N*L) до O(N*L_local), и при этом нет G-Buffer overhead и проблем с прозрачностью.
**Material variety**: deferred ограничивает разнообразие шейдеров - все материалы должны укладываться в фиксированный G-Buffer (BRDF параметры). Forward позволяет полностью кастомные шейдеры на объект.
Команда делает гоночный симулятор: 50 машин (uniform PBR), 200+ источников света от фонарей, отражения. Какой rendering pipeline?
Tiled Shading
Lighting pass в deferred всё ещё дорог: при 1000 светах каждый пиксель итерируется по всем 1000. Большинство светов локальны (точка, прожектор) и затрагивают малую область экрана. **Tiled shading** разбивает экран на тайлы 16x16 или 32x32 пикселя; для каждого тайла предварительно вычисляется список источников света, пересекающих его область. Затем lighting pass итерируется только по локальному списку.
Алгоритм: (1) Compute shader проходит по тайлам параллельно. (2) Для каждого тайла строит frustum (sub-frustum экрана). (3) Проверяет AABB каждого источника света против frustum. (4) Записывает индексы пересекающихся светов в SSBO. Lighting shader для пикселя берёт список светов своего тайла и итерируется только по ним.
**Tile size trade-off**: маленький тайл (8x8) = меньше светов на тайл, но больше overhead в culling. Большой тайл (64x64) = быстрый culling, но больше ложноположительных светов на пиксель. Типичный balance - 16x16.
В чём принципиальное преимущество tiled shading перед обычным deferred lighting?
Clustered Shading
Tiled shading работает в 2D - каждый тайл это столбик от near до far plane. Если в одном тайле есть и близкий и далёкий объект, лиственная улица и здание вдалеке делят список светов. **Clustered shading** добавляет третье измерение: разбивает frustum на 3D-сетку кластеров (например, 16x16x32), где каждый кластер - часть тайла на определённой глубине. Свет 'факел в коридоре' попадает только в близкие кластеры, дальний skybox-свет - только в дальние.
Clustered shading использован в Doom 2016, Doom Eternal, Detroit: Become Human - и считается эталоном для real-time с большим количеством источников света. Деление по глубине обычно логарифмическое (Z в clip space неоднороден). Хранение списков светов - sparse 3D-grid + индексные таблицы.
**Clustered + Forward+ + ray tracing** - современная гибридная архитектура (Doom Eternal, Unreal 5 Lumen): clustered для большинства светов, ray tracing для select few с высоким impact (солнце, ключевые сюжетные источники).
Deferred rendering всегда быстрее forward; современные движки используют только deferred.
Deferred быстрее при многих источниках света и единообразных материалах; forward+ с clustered culling быстрее при разнообразных материалах и прозрачности; реальные движки используют гибрид.
Каждая техника оптимальна в своём профиле. Doom Eternal на clustered forward+ обгоняет deferred-движки на той же сцене за счёт отсутствия G-Buffer overhead.
Зачем clustered shading нужно третье измерение по глубине?
Ключевые идеи
- **G-Buffer** разделяет geometry pass и lighting pass, превращая O(N * L) в O(N + pixels * L) - решение многих светов
- **Deferred vs Forward+** - не победа одного над другим, а компромисс: deferred хорош для PBR с многими светами, forward+ - для разнообразных материалов и transparency
- **Tiled shading** разбивает экран на 16x16 тайлов с локальными списками светов - экономия 100x на lighting pass
- **Clustered shading** добавляет 3D-глубину: близкие и далёкие пиксели в одном тайле получают разные списки светов
- Современные движки - гибрид: clustered + forward+ для основной сцены, deferred для opaque PBR, ray tracing для select effects
Связанные темы
Возвращаясь к Doom Eternal: clustered shading - это computational geometry в action (3D-сетка culling против сфер света), решающая проблему освещения для real-time. Эта тема связана с:
- PBR (Physically Based Rendering) — G-Buffer хранит параметры PBR (metallic, roughness, normal); deferred pipeline идеально ложится на PBR-материалы
- Computational Geometry: интервью — Light culling - frustum vs sphere - это AABB-intersection из computational geometry; clustered shading использует те же примитивы
Вопросы для размышления
- Ray tracing real-time стал доступен с RTX 20xx (2018). Заменит ли он deferred/clustered shading через 5-10 лет, или будет работать в гибриде ещё долго?
- Mobile GPU (Adreno, Mali) имеют tile-based architecture на уровне железа. Делает ли это tiled shading менее ценным на mobile - или наоборот, более естественным?
- Современные движки тратят значительную часть бюджета на G-Buffer (150+ МБ VRAM, bandwidth). Где разумная граница: когда G-Buffer становится дороже самой проблемы, которую он решает?
Связанные уроки
- cg-08 — G-буфер - это вывод geometry stage в Deferred Rendering pipeline
- cg-13 — RTX и Deferred - две стратегии для сложной сцены, противоположные подходы
- cg-15 — Post-effects читают из G-буфера Deferred Rendering
- arch-15-gpu-architecture — Bandwidth и VRAM - узкое место Deferred, нужно понимать GPU memory
- arch-09-cache