SSAO простыми словами: что это за затенение в 3D-графике

SSAO простыми словами: что это за затенение в 3D-графике Полезное

SSAO (screen space ambient occlusion, окружающее затенение в экранном пространстве) — это техника рендеринга, которая затемняет углы, щели и места контакта объектов, приближая эффект рассеянного затенения по тому, что видно на экране. Работает в реальном времени на видеокарте.

SSAO придумали в Crytek для игры Crysis (движок CryEngine 2, 2007 год); сейчас та же идея встроена в Unity, Unreal и другие движки. Ниже разберу, что такое ambient occlusion, почему приставка screen space меняет и цену, и качество, покажу механику на прогоняемом примере и сравню SSAO с HBAO, GTAO и трассировкой лучей.

Ambient occlusion: что именно затемняем

Рассеянный (ambient) свет приходит к поверхности со всех сторон сразу — как в пасмурный день, без резких теней. В открытом месте точка получает свет почти со всех направлений. А в углу комнаты, в щели между предметами или под объектом часть направлений перекрыта соседней геометрией, и света доходит меньше.

Ambient occlusion (AO) — это как раз доля перекрытых направлений: мягкое затемнение в углах, стыках и под предметами. Именно оно создает ощущение, что объекты стоят на поверхности, а не парят над ней.

Здесь важно развести два близких понятия. AO — это не глобальное освещение. Глобальное освещение (GI) считает, как свет отражается от поверхностей и подсвечивает другие, вплоть до переноса цвета. AO только приглушает рассеянный свет в закрытых местах и ничего не подсвечивает. SSAO приближает именно AO, а не полный GI, — поэтому описывать его как «систему глобального освещения» неточно.

Почему screen space: как работает SSAO

Честный ambient occlusion надо считать по всей трехмерной геометрии сцены — для реального времени это дорого. SSAO идет на упрощение: оценивает затенение только по тому, что уже нарисовано на экране, — по буферу глубины (глубина каждого пикселя), иногда дополняя его буфером нормалей.

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

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

Механика на маленьком примере

Соберу крошечный буфер глубины: плоский пол и приподнятый объект, который ближе к камере. Затем для каждого пикселя посчитаю затенение по соседям — примерно так же, как это делает шейдер. Меньшая глубина значит ближе к камере.

# Мини-модель SSAO: затенение считаем ТОЛЬКО по буферу глубины (экранное пространство).
# depth = расстояние от камеры до пикселя (меньше = ближе к камере).
W, H = 16, 8
FLOOR = 20            # глубина фона-пола
BOX = 8               # глубина приподнятого объекта (ближе к камере)
BIAS = 3              # порог: сосед считается преградой, если он ближе больше чем на BIAS
RADIUS = 1            # радиус выборки соседних пикселей на экране

# 1. Собираем буфер глубины: пол + прямоугольный объект ближе к камере
depth = [[FLOOR] * W for _ in range(H)]
for y in range(2, 6):
    for x in range(6, 11):
        depth[y][x] = BOX

# 2. Для каждого пикселя считаем окклюзию по соседям в буфере глубины
def occlusion(cx, cy):
    occluders = samples = 0
    for dy in range(-RADIUS, RADIUS + 1):
        for dx in range(-RADIUS, RADIUS + 1):
            if dx == 0 and dy == 0:
                continue
            x, y = cx + dx, cy + dy
            if 0 <= x < W and 0 <= y < H:
                samples += 1
                # сосед заметно ближе к камере -> он перекрывает рассеянный свет
                if depth[cy][cx] - depth[y][x] > BIAS:
                    occluders += 1
    return occluders / samples if samples else 0.0

# 3. Рендерим карту освещенности: ao = 1 - окклюзия (1.0 = полный свет, 0.0 = тень)
ramp = " .:-=+*#"   # от темного к светлому
print("Карта освещенности (@ = объект, темнее = сильнее затенено):")
for y in range(H):
    row = ""
    for x in range(W):
        if depth[y][x] == BOX:
            row += "@"
            continue
        ao = 1 - occlusion(x, y)
        row += ramp[int(ao * (len(ramp) - 1))]
    print(row)

# 4. Числа для трех характерных пикселей
print()
print("пол вдали (2,2):     окклюзия =", round(occlusion(2, 2), 2))
print("пол у основания (5,3): окклюзия =", round(occlusion(5, 3), 2))
print("угол под объектом (5,5): окклюзия =", round(occlusion(5, 5), 2))

Вывод программы:

Карта освещенности (@ = объект, темнее = сильнее затенено):
################
#####*+===+*####
#####+@@@@@+####
#####=@@@@@=####
#####=@@@@@=####
#####+@@@@@+####
#####*+===+*####
################

пол вдали (2,2):     окклюзия = 0.0
пол у основания (5,3): окклюзия = 0.38
угол под объектом (5,5): окклюзия = 0.25

Пол вдали от объекта получает полный свет (символ #): у него нет близких соседей, окклюзия 0. А пол вокруг основания объекта затемняется (=, +, *): рядом есть пиксели, которые ближе к камере, и они перекрывают часть рассеянного света. Так и появляется мягкая контактная тень у подножия предмета.

Это упрощенная иллюстрация принципа «сосед ближе — значит затеняет». Настоящий SSAO работает в непрерывных координатах вида, учитывает нормали поверхности и вес по расстоянию, но идея та же: затенение оценивается по буферу глубины, а не по полной 3D-сцене.

Артефакты и границы SSAO

Раз метод видит только экран, у него есть характерные слабые места. Знать их полезно: по ним SSAO и опознают в кадре.

  • Что вне экрана или спрятано за другим объектом, не затеняет: у краев экрана затенение обрывается.
  • Зависимость от камеры: повернул или подвинул обзор — затенение слегка «поплыло», потому что меняется набор видимых пикселей.
  • Ореолы (halo): светлые или темные каемки на резких перепадах глубины, вокруг силуэтов объектов.
  • Шум и мерцание в движении, если выборок мало или размытие слабое.

Это плата за упрощение. Более поздние методы (ниже) борются именно с этими артефактами, но ни один screen-space способ полностью от них не избавлен — он по определению ограничен видимым кадром.

SSAO и его развитие: HBAO, GTAO, трассировка лучей

SSAO — самый ранний и дешевый вариант, но не единственный. Развитие шло в сторону меньшего числа артефактов и большей близости к эталонному AO, обычно ценой производительности.

Метод Что использует Точность и артефакты Стоимость для GPU
SSAO буфер глубины экрана грубая оценка, заметные ореолы и шум низкая
HBAO / HBAO+ глубину + оценку «горизонта» вокруг точки точнее SSAO, HBAO+ убирает часть мерцания средняя
HDAO вариант AMD на основе глубины близка к HBAO по идее средняя
GTAO приближение к эталонному AO по экрану заметно меньше ореолов, мягкие контакты средняя, выше SSAO
VXAO воксельное представление сцены учитывает геометрию вне экрана высокая
RTAO трассировку лучей по реальной геометрии почти без screen-space артефактов высокая

Пара уточнений к названиям. HBAO — это Horizon-Based Ambient Occlusion (затенение на основе горизонта), а не «Based Ambient Occlusion». RTAO — это ambient occlusion через трассировку лучей: лучи из точки проверяют настоящую геометрию, а не соседние пиксели, поэтому уходит главный недостаток screen space. Но трассировка требует видеокарты с аппаратной поддержкой и заметно грузит кадр.

Отдельно про RTX: это линейка видеокарт Nvidia с аппаратной трассировкой, а не сама техника затенения. Трассированный AO работает и на других GPU с аппаратной трассировкой лучей, а не только на RTX.

Включать SSAO или нет

В настройках графики ambient occlusion обычно вынесен отдельным переключателем — как «SSAO», «HBAO», «AO» или уровнем качества. Что дает включение и о чем помнить:

  • Плюс: мягкие тени в углах и под предметами и ощущение объема почти бесплатно по сравнению с полным расчетом освещения.
  • Минус: это дополнительный полноэкранный проход на GPU. На слабой видеокарте он ощутим, и если кадр проседает, AO снижают или отключают одним из первых.
  • Если в кадре видны темные каемки вокруг объектов или мерцание при движении — стоит попробовать другой режим (HBAO, GTAO) или снизить качество AO.

Нагрузка ложится в основном на видеочип; центральный процессор в расчете AO почти не участвует. Поэтому на системах, где узкое место — именно GPU, эффект от отключения AO заметнее всего.

Выводы

  • SSAO (screen space ambient occlusion) — дешевая техника затенения углов, щелей и контактов объектов по буферу глубины, в реальном времени на GPU.
  • SSAO приближает ambient occlusion, а не глобальное освещение: оно затемняет закрытые места, но не переносит и не отражает свет.
  • «Экранность» дает и скорость, и артефакты: обрывы у краев кадра, ореолы, зависимость от угла камеры, шум в движении.
  • Развитие метода — HBAO/HBAO+, HDAO, GTAO, VXAO и RTAO через трассировку лучей: точнее, но дороже для видеокарты.
  • В настройках AO — отдельный переключатель; при нехватке кадров его снижают или меняют режим одним из первых.

Где применяется и связь с практикой

Ambient occlusion — штатная часть конвейера рендеринга в любом современном движке. В Unity, например, SSAO настраивается как эффект пост-обработки в конвейерах URP и HDRP: включается вместе с прочим освещением, и от его параметров зависит, насколько «посаженными» на поверхность выглядят объекты сцены.

Освойте тему на практике

Разобраться, как рендеринг, освещение и постобработка собираются в готовую сцену на практике, помогает курс Unity Game Developer. Basic — там графика идет вместе с логикой игры на реальном проекте. Посмотреть формат и уровень до старта можно на бесплатных открытых уроках Otus — это живые занятия с преподавателями.

FAQ

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

Сильно ли SSAO бьет по FPS? Это дополнительный полноэкранный проход на видеокарте. По сравнению с полным расчетом освещения он дешев, но на слабом GPU просадка заметна — тогда AO снижают или отключают в первую очередь.

Нужен ли SSAO, если включена трассировка лучей? Обычно нет: трассированный AO (RTAO) заменяет экранный и дает результат без screen-space артефактов. Включать оба режима AO одновременно смысла нет.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)