Ambient Occlusion: від SSAO до GTAO

🎨 Комп'ютерна графіка ⏱ ~9 хв читання Середній рівень
SSAO HBAO GTAO Screen Space Глобальне освітлення

Ambient occlusion апроксимує те, для чого глобальне освітлення зазвичай потребує повної симуляції транспорту світла: м'яке затемнення у кутах, складках і точках контакту, де сусідня геометрія блокує вхідне навколишнє світло. З того часу, як Crysis у 2007 році популяризував screen-space AO, техніка пройшла кілька поколінь — SSAO (Screen-Space Ambient Occlusion, «екранне» навколишнє затінення), HBAO, HBAO+ і сьогоднішній GTAO — кожне з яких скорочувало розрив між дешевим screen-space хаком і фізично коректною відповіддю, яку дав би path tracer.

Коротко: Ambient occlusion імітує затемнення в кутах і точках контакту, яке дало б повне глобальне освітлення, без реального трасування променів світла. Технології реального часу пройшли шлях від шумного випадкового семплінгу півсфери в SSAO (2007) через пошук горизонту в HBAO до точного інтеграла по зрізах горизонту з часовим накопиченням у GTAO — кожне покоління наближало результат до якості трасування променів ціною продуктивності.

1. Інтеграл оклюзії

Ambient occlusion у точці поверхні p з нормаллю n визначається як частка півсфери над p, не заблокована сусідньою геометрією, проінтегрована з косинусною вагою (той самий косинусний член, що і в рівнянні рендерингу, але з видимістю V замість повного радіансу):

AO(p) = 1 − (1/π) ∫_Ω V(p, ω) · (n·ω) dω

V(p, ω) = 0, якщо сусідня поверхня блокує напрямок ω в межах радіуса r, інакше 1

AO у діапазоні [0,1]: 1 = повністю відкрито, 0 = повністю заблоковано (глибока щілина)

Повна відповідь через трасування променів пускає сотні променів на піксель і перевіряє перетин зі сценою для кожного — саме це вже обчислює path tracer як побічний ефект глобального освітлення. Кожна з технік реального часу нижче — апроксимація того самого інтеграла у набагато жорсткішому часовому бюджеті — зазвичай менше 1 мс за кадр.

2. SSAO: випадковий семплінг півсфери у просторі глибини

SSAO від Crytek (Mittring, 2007) апроксимує інтеграл, використовуючи лише буфер глибини, вже доступний після проходу геометрії — без додаткового обходу сцени, без BVH. Для кожного пікселя береться жменька точок у ядрі-півсфері навколо точки поверхні, їхня позиція у view space реконструюється і порівнюється з буфером глибини, щоб вгадати, чи вони заблоковані.

// SSAO фрагментний шейдер, спрощено
vec3 pos    = reconstructViewPos(gl_FragCoord.xy, depthTex);
vec3 normal = texture(normalTex, uv).xyz;
vec3 tangent = normalize(texture(noiseTex, uv * noiseScale).xyz);
mat3 tbn = buildTBN(normal, tangent);

float occlusion = 0.0;
for (int i = 0; i < kernelSize; i++) {
  vec3 samplePos = pos + tbn * kernel[i] * radius;
  vec4 offset = projection * vec4(samplePos, 1.0);
  offset.xyz /= offset.w;
  offset.xyz = offset.xyz * 0.5 + 0.5;

  float sceneDepth = linearizeDepth(texture(depthTex, offset.xy).r);
  float rangeCheck = smoothstep(0.0, 1.0, radius / abs(pos.z - sceneDepth));
  occlusion += (sceneDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck;
}
float ao = 1.0 - (occlusion / float(kernelSize));

Це дешево, але грубувато: техніка знає лише про глибину, а не про реальну геометрію, тож може пропустити оклюдери позаду видимої поверхні (неповнота screen-space) і потребує 16–64 зразків на піксель, щоб уникнути сильного шуму.

3. Шум, блюр і компроміс з кількістю зразків

З малим ядром вихід SSAO помітно шумний — випадкове поворотне ядро для кожного пікселя (через невелику тайловану текстуру шуму) обмінює структуроване смугування на менш помітний високочастотний шум, який потім прибирається білатеральним блюром (враховуючи глибину/нормаль, щоб AO не "перетікав" через силует-краї).

Розмір ядраСирий шумТиповий радіус блюруВартість
8–16 зразківДуже шумно5×5–7×7Найдешевше
16–32 зразкиПомірно4×4Збалансовано (більшість ігор)
64+ зразківМало3×3Дорого, рідко без обробки

4. HBAO: оклюзія на основі горизонту

Horizon-Based Ambient Occlusion (Bavoil, Sainz, Dimitrov — NVIDIA, 2008) переформульовує задачу геометрично замість довільних семплів у півсфері: для кожного з кількох напрямків навколо пікселя у screen space, маршуємо назовні вздовж буфера глибини, щоб знайти "кут горизонту" — найвищий кут піднесення, під яким сусідня геометрія блокує півсферу.

Для напрямку φ: кут горизонту h(φ) = максимальний кут піднесення будь-якої зразкової точки вздовж цього напрямку

Внесок AO від цього напрямку ∝ sin(h(φ)) − sin(t(φ))

t(φ) = кут дотичної площини у p (враховує нахил поверхні відносно погляду)

Інтегруємо по кількох напрямках φ (зазвичай 4–8) → фінальний AO

Оскільки техніка маршує вздовж реальних зразків буфера глибини, а не перевіряє довільні зміщені точки, HBAO точніше вловлює тонкі оклюдери та контактні тіні, ніж SSAO на основі ядра, за подібну або трохи вищу вартість. HBAO+ (2013) додав блюр, що зберігає деталі, і апроксимацію багатократних відбиттів кольору.

5. GTAO: ambient occlusion на основі точного розв'язку

Ground Truth Ambient Occlusion (Jimenez та ін., Activision, 2016) зберігає структуру пошуку горизонту з HBAO, але замінює її наближений косинусно-зважений інтеграл точним аналітичним розв'язком для інтеграла видимості, обмеженого дугою горизонту — звідси "ground truth": для заданого горизонту це математично коректний внесок AO, а не евристика.

Точний інтеграл по зрізу (Jimenez 2016):

InnerIntegral(h1,h2,n) = ¼·(−cos(2h1−γ) + cosγ + 2h1·sinγ − cos(2h2−γ) + cosγ + 2h2·sinγ)

де γ — кут між спроєктованою нормаллю та площиною зрізу

Результат: візуально майже ідентичний трасованому AO при набагато меншій кількості зразків горизонту, ніж потрібно HBAO для тієї ж якості

GTAO зазвичай використовує лише 2 напрямки зрізу з кількома кроками горизонту у кожному, поєднані з сильним темпоральним накопиченням (повторне використання зразків попередніх кадрів через репроекцію), щоб досягти переконливої якості за частку вартості HBAO+ за кадр — саме ця техніка стоїть за AO за замовчуванням у більшості сучасних ігрових рушіїв (Unreal, багато власних рушіїв).

6. Апроксимація багатократних відбиттів і колір, забарвлений AO

Чистий AO лише затемнює — у нього немає кольору, оскільки він призначений модулювати навколишнє/непряме світло, а не пряме. Реальне непряме світло відбивається від кольорових поверхонь перед тим, як повернутись, тож наївний AO, застосований до кольорових сцен (скажімо, червоної кімнати), виглядає надто темним і сірим у кутах. Multi-bounce GTAO апроксимує це, пропускаючи базовий альбедо через поліноміальну апроксимацію, каліброван проти еталонного path-traced багатократного GI, освітлюючи і забарвлюючи член оклюзії замість того, щоб лишати його плоским сірим множником.

Однократний AO

Простий сірий множник для навколишнього світла. Швидко, але щілини у кольорових сценах виглядають неприродно темними.

Multi-bounce GTAO

Поліноміальна корекція з використанням альбедо поверхні — кути забарвлені у відбитий колір, ближче до еталонного GI.

Ray-traced AO (RTAO)

Справжні апаратні промені проти реальної геометрії сцени, без обмеження screen-space, але потребує RT-заліза.

7. Порівняння та нотатки з реалізації

ТехнікаРікОсновна ідеяТипова вартість
SSAO2007Випадкове ядро-півсфера проти буфера глибиниНизька, але шумна при малій кількості зразків
HBAO2008Пошук горизонту вздовж буфера глибиниПомірна, краща геометрична точність
HBAO+2013HBAO + блюр зі збереженням деталей, апрокс. багатократних відбиттівПомірна–висока
GTAO2016Точний інтеграл по зрізу горизонту + темпоральне перевикористанняНизька з TAA, висока якість

Для WebGL2/WebGPU-реалізації практичний пайплайн такий: прохід глибини + нормалей → compute-прохід AO (SSAO-ядро або пошук горизонту GTAO) у половинній чи повній роздільності → білатеральний блюр → множення лише у навколишній/непрямий член освітлення (ніколи у пряме світло чи emissive). Темпоральне перевикористання GTAO потребує векторів руху та буфера репроекції, що додає реальну складність реалізації — розумний середній варіант для браузерної демонстрації — пошук горизонту у стилі HBAO без темпорального накопичення, натомість з просторовим шумозаглушенням.

💡 Відкрити демо Path Tracing →

🔗 Пов'язані симуляції

💡Path Tracing ✳️Фрактал