Компьютерная графика
Пост-обработка: Bloom, DoF, Motion Blur, Tone Mapping
Cyberpunk 2077 в момент выхода в 2020 году продал 13 миллионов копий за 10 дней - рекорд для PC. Критики отмечали кинематографичность визуала. За этим стоит не более детализированная геометрия, а пост-обработка: HDR Bloom, Bokeh DoF, ACES tone mapping. Одни и те же полигоны с пост-процессингом и без выглядят как разные игры.
- Cyberpunk 2077: Bloom + ACES tone mapping дают неоновые огни без пересвета на улицах Найт-Сити
- God of War: кинематографический DoF с hexagonal bokeh на портретных сценах в реальном времени
- Unreal Engine 5: Temporal Super Resolution с motion blur velocity buffer для 4K из 1080p
- Horizon Forbidden West: per-object motion blur для персонажей через отдельный skinned velocity pass
Bloom: почему яркий свет светится
Матрица камеры физически не может передать диапазон яркостей солнечного дня - 100 000 : 1 против 255 : 1 у SDR-экрана. Bloom не «добавляет свечение» - он имитирует оптическое рассеяние в линзе, которое происходит именно тогда, когда сцена в HDR.
**Пайплайн Bloom:** 1) рендер сцены в HDR-буфер (16f RGB); 2) threshold-pass - выбрать пиксели с яркостью > 1.0; 3) downscale до 1/2, 1/4, 1/8, 1/16; 4) двойной Gauss blur (сначала по X, затем по Y) на каждом mip; 5) upscale с additive blend обратно в full-res; 6) сложить с оригиналом перед tone mapping. Разделённый Gauss (2 прохода по 1D) даёт O(n) вместо O(n²) для 2D-ядра.
**Dual Kawase vs Gauss.** Unreal Engine 4 использует Dual Kawase blur вместо Gauss - он требует вдвое меньше текстурных выборок при схожем результате. Принцип: каждый downscale-pass читает 4 соседних пикселя со смещением +0.5, что даёт Gauss-подобное размытие без явного ядра.
Почему Gaussian blur при Bloom разбивается на два прохода - по X и по Y?
Depth of Field: размытие по кругу рассеяния
В реальной камере объекты вне фокусной плоскости проецируются не в точку, а в диск - Circle of Confusion (CoC). Чем больше диск, тем сильнее объект размыт. GPU-DoF воспроизводит эту геометрию, используя глубину из G-буфера.
**Gather vs Scatter DoF.** Gather: каждый пиксель собирает вклады из радиуса CoC (описан выше). Scatter: каждый яркий пиксель «разбрасывает» bokeh-диски на соседей - физически точнее, но требует vertex shader instancing и alpha blend без depth test. Unreal Engine 5 использует Scatter для ярких источников света и Gather для фона.
Что такое Circle of Confusion (CoC) в контексте Depth of Field?
Motion Blur: размытие движения из velocity-буфера
Без motion blur анимация в 30 fps выглядит дёрганой даже на быстром GPU - каждый кадр слишком чёткий. Реальная камера интегрирует свет за время выдержки (1/60 с), смазывая движущиеся объекты. GPU имитирует это за один пост-процессинг проход.
**Screen-Space Velocity Buffer.** Во время G-буфер прохода вершинный шейдер вычисляет разницу между текущей и предыдущей позицией каждого пикселя в NDC: `velocity = (currentNDC - prevNDC) * 0.5`. Пост-процессинг шейдер читает velocity-вектор и делает N выборок вдоль него, усредняя цвет. Количество выборок = 8..16 для игр, 32+ для кинематографии.
**Per-object vs camera motion blur.** Velocity buffer из NDC-разницы автоматически учитывает и движение камеры, и движение объектов. Но скинированные персонажи требуют velocity от каждой кости. Unreal Engine хранит отдельный skinned velocity буфер для Skeletal Mesh - это дополнительный geometry pass, но критичен для корректного blur'а персонажей.
Как velocity buffer используется для motion blur?
Tone Mapping: из HDR в то, что видит экран
После Bloom, DoF и Motion Blur HDR-буфер содержит значения яркости от 0 до 10 000 нит. Экран показывает 0..255. Tone mapping - это нелинейное сжатие этого диапазона с сохранением деталей в тенях и светах. Без него весь bright region становится белым, весь dark region - чёрным.
**ACES и Display-P3.** ACES (Academy Color Encoding System) разработан киноиндустрией в 2014 году. Epic Games перевела Unreal Engine на ACES в UE4.15. Современные iPhone используют Display-P3 (DCI-P3 с D65) - цветовое пространство шире sRGB на 25%. Для корректного рендеринга нужно знать целевое пространство ещё до tone mapping.
Tone mapping и gamma correction - одно и то же
Tone mapping сжимает HDR в LDR с учётом перцептивных характеристик (S-кривая). Gamma correction переводит линейное пространство в sRGB (степень 1/2.2). Это разные операции: сначала tone mapping, потом gamma.
Ошибка приводит к тому, что яркие блики становятся белыми без деталей (пересвет), а тени теряют контраст. ACES + gamma дают кинематографичный результат, Reinhard без gamma - плоский и бледный.
Зачем нужен tone mapping и где он применяется в пайплайне?
Ключевые идеи
- Bloom: HDR threshold -> downscale mip chain -> двойной 1D Gauss (сепарабельный, O(n)) -> additive upscale
- DoF: Circle of Confusion из глубины G-буфера -> gather N выборок по CoC-радиусу (hexagonal bokeh)
- Motion Blur: velocity = текущий NDC - предыдущий NDC -> N выборок вдоль вектора -> усредение
- Tone Mapping: последний шаг - сжать HDR в LDR с S-кривой (ACES) -> gamma correction -> экран
- Порядок пайплайна: G-buffer -> lighting HDR -> Bloom -> DoF -> Motion Blur -> Tone Mapping -> gamma
Связанные темы
Пост-обработка завершает HDR пайплайн, начатый в Deferred Rendering.
- Deferred Rendering — G-буфер с глубиной и velocity - фундамент всех пост-эффектов
- GPU Graphics Pipeline — Fullscreen quad render target - базовая техника всех пост-процессинг шейдеров
- Terrain и LOD — Terrain рендерится в тот же HDR-буфер и проходит через тот же пост-пайплайн
Вопросы для размышления
- Почему Bloom нужно применять до tone mapping, а не после? Что изменится если поменять порядок?
- Как Temporal Anti-Aliasing использует тот же velocity buffer, что и motion blur, но для разной задачи?
- ACES - стандарт киноиндустрии. Какие компромиссы у него есть по сравнению с Reinhard для игр с яркими HUD-элементами?
Связанные уроки
- cg-14 — Deferred Rendering даёт G-буфер, на котором строятся все пост-эффекты
- cg-08 — Compute шейдер и текстурный пайплайн - основа всех fullscreen-эффектов
- cg-16 — Terrain LOD завершает пайплайн с тем же HDR-буфером
- dsp-04 — Bloom и DoF - это свёрточные фильтры: Гаусс и bokeh-ядро из теории ЦОС
- arch-09-cache