🖥️ Графіка та рендеринг · Шейдинг
📅 Квітень 2026⏱ 16 хв🔴 Просунутий рівень · Останнє оновлення: 3 липня 2026 р.

Фізично коректний рендеринг (PBR): теорія і практика

Кожна AAA-гра, випущена з 2014 року, використовує фізично коректний рендеринг. Причина переконлива: єдиний набір параметрів матеріалу — альбедо, шорсткість, металічність — дає узгоджені, правдоподібні результати за всіх умов освітлення, від яскравого сонячного світла до глибокої тіні. PBR замінив довільні шейдери Фонга та Блінна-Фонга, заґрунтувавши модель освітлення на фізиці розсіювання світла на поверхнях. Ця стаття охоплює рівняння рендерингу, теорію мікрограней, BRDF Кука-Торренса, робочий процес metalness/roughness та освітлення на основі зображень — з повною реалізацією на GLSL.

1. Рівняння рендерингу

Рівняння рендерингу (Kajiya 1986) — головне рівняння фотореалістичного рендерингу. Воно описує вихідну яскравість з будь-якої точки поверхні в будь-якому напрямку як суму випроміненої яскравості та відбитої яскравості з усіх вхідних напрямків:

// Рівняння рендерингу (Kajiya 1986) Lₒ(p, ωₒ) = Lₑ(p, ωₒ) + ∫_Ω f(p, ωᵢ, ωₒ) Lᵢ(p, ωᵢ) (n·ωᵢ) dωᵢ Де: p = точка поверхні ωₒ = вихідний напрямок (до камери) ωᵢ = вхідний напрямок (від джерела світла) Lₒ(p, ωₒ) = вихідна яскравість (те, що ми хочемо обчислити) Lₑ(p, ωₒ) = випромінена яскравість (емісійні матеріали: екрани, джерела світла) Lᵢ(p, ωᵢ) = вхідна яскравість (від оточення або джерел світла) f(p,ωᵢ,ωₒ) = BRDF: скільки вхідного світла розсіюється до ωₒ n·ωᵢ = косинус кута між нормаллю та вхідним світлом (множник Ламберта) ∫_Ω = інтеграл по верхній півсфері напрямків BRDF (двопроменева функція розподілу відбиття): f : [ср⁻¹] — відношення вихідної яскравості до вхідної освітленості Має задовольняти збереження енергії: ∫_Ω f(ωᵢ,ωₒ)(n·ωᵢ) dωᵢ ≤ 1 Має задовольняти взаємність Гельмгольца: f(ωᵢ,ωₒ) = f(ωₒ,ωᵢ)

Рівняння рендерингу не розв'язується безпосередньо в реальному часі — інтеграл по півсфері за всіма вхідними напрямками містить Lᵢ, що залежить від геометрії всієї сцени. PBR реального часу робить два наближення: (1) обчислює аналітично лише скінченну кількість джерел світла та (2) опрацьовує внесок оточення окремо через попередньо обчислене освітлення на основі зображень.

2. Теорія мікрограней

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

// Поняття мікрограней Нормаль макроповерхні: N (нормаль, яку б ви виміряли лінійкою) Нормаль мікрограні: H (піввектор між ωᵢ та ωₒ) H = normalize(ωᵢ + ωₒ) Ключова ідея: лише мікрограні, чия нормаль дорівнює H, дають внесок у відбиття від ωᵢ до ωₒ (дзеркальне відбиття = відбиття як у дзеркала) Шорсткість α: α = roughnessParameter² (або просто roughnessParameter, конвенція різниться) α → 0: дзеркальна поверхня (усі мікрограні вирівняні → різкий відблиск) α → 1: дифузноподібна (широко розподілені нормалі → широкий відблиск) Три фізичні ефекти, описувані BRDF: 1. D(H) — функція розподілу нормалей: яка частка мікрограней спрямована до H? (керує формою та розміром відблиску) 2. G(ωᵢ, ωₒ) — геометричне затінення-маскування: деякі мікрограні затінені іншими або маскують відбите світло 3. F(ωᵢ, H) — Френель: відбивна здатність залежить від кута огляду

3. Компоненти BRDF: D, G, F

D — функція розподілу нормалей GGX

NDF GGX (Троубриджа-Райца) — галузевий стандарт, що дає дзеркальний відблиск з різкішим піком та довшими хвостами, ніж Беккмана чи Блінна-Фонга — точніше відповідаючи реальним вимірюванням шорстких поверхонь:

// Функція розподілу нормалей GGX D_GGX(N, H, α) = α² / (π · ((N·H)² · (α²−1) + 1)²) Де: α = roughness² (перцептивна шорсткість у квадраті для лінійнішого відчуття) N·H = косинус кута між нормаллю поверхні та піввектором Властивості: - D = щільність імовірності мікрограней, орієнтованих до H - ∫_Ω D(H)(N·H) dH = 1 (за визначенням розподілу) - При α=0: дельта-функція (ідеальне дзеркало — нескінченно різкий відблиск) - При α=1: широкий косинусоподібний розподіл (дуже шорстко) - «Довгий хвіст» проти Беккмана: реалістичніший для шорстких матеріалів

G — геометрична функція Сміта

// Геометричне затінення-маскування Сміта (наближення Шліка) // Враховує затінення мікрограней (вхідне) або маскування (вихідне) G_SchlickGGX(NdotV, α) = NdotV / (NdotV · (1−k) + k) де k = α/2 (для прямого освітлення) k = (α+1)²/8 теж видається популярним // Повна G Сміта (сепарабельне наближення): G_Smith(N, V, L, α) = G_SchlickGGX(N·V, α) · G_SchlickGGX(N·L, α) // У поєднанні зі знаменником у Кука-Торренсі: // Знаменник 1/(4(N·V)(N·L)) часто об'єднують з G для стійкості

F — Френель (наближення Шліка)

// Наближення Френеля-Шліка F_Schlick(F0, V, H) = F0 + (1 − F0) · (1 − V·H)⁵ Де: F0 = відбивна здатність за нормального падіння (кут 0°) = ((n₁ − n₂)/(n₁ + n₂))² (із закону Снеліуса за нормального падіння) Значення F0 матеріалів (приблизні): Вода: F0 = 0.02 (2% відбиття в лоб) Скло: F0 = 0.04 Пластик: F0 = 0.04–0.06 Срібло: F0 = vec3(0.95, 0.93, 0.88) (металеве — залежить від довжини хвилі) Золото: F0 = vec3(1.00, 0.71, 0.29) (металеве — характерний золотистий відтінок) Алюміній: F0 = vec3(0.91, 0.92, 0.92) Ефект Френеля: за ковзних кутів (V·H → 0): усі матеріали стають майже на 100% відбивними Саме тому краї об'єктів завжди показують сильні дзеркальні відблиски Чому мокрі дороги виглядають дзеркальними, коли дивитися під малим кутом

4. BRDF Кука-Торренса повністю

// Дзеркальний BRDF мікрограней Кука-Торренса f_specular(ωᵢ, ωₒ) = D(H) · G(ωᵢ, ωₒ) · F(ωᵢ, H) ─────────────────────────────── 4 · (N·ωᵢ) · (N·ωₒ) // Дифузний BRDF (Ламбертів): f_diffuse = c_diffuse / π (сталий, ізотропний) // Збереження енергії: kS + kD = 1 // kS = F (множник Френеля — частка, що йде в дзеркальне) // kD = (1 − F) · (1 − metalness) (немає дифузного для металів) // Метали: усе поглинуте світло стає дзеркальним (F0 з альбедо) // Діелектрики: дифузне альбедо дає внесок у член kD // Повний BRDF: f(ωᵢ, ωₒ) = kD · f_diffuse + kS · f_specular // Інтеграл відбиття для одного точкового джерела світла: Lₒ = (f_diffuse · kD + f_specular) · Lᵢ · (N·L) · lightColor // Важливість: знаменник 4(N·ωᵢ)(N·ωₒ) запобігає приросту енергії // та переводить з простору піввектора в простір напрямку світла

5. Робочий процес metalness/roughness

Disney (Burley 2012) популяризував зручну для художників параметризацію «metalness/roughness», яку використовують більшість сучасних рушіїв та інструментів (Substance Painter, Blender, UE5, Unity):

// Текстурні карти PBR у робочому процесі metalness/roughness albedo (baseColor): sRGB RGB — дифузний колір для діелектриків, відбивний колір для металів roughness: лінійний R — перцептивна шорсткість ∈ [0,1] metalness: лінійний R — 0=діелектрик, 1=метал (зазвичай бінарний) normal: карта нормалей у дотичному просторі AO: ambient occlusion (попередньо запечений множник тіні) emissive: самовипромінювальні ділянки (екрани, неонові вивіски) // Виведення F0 та дифузного альбедо з художніх вхідних даних: vec3 F0 = mix(vec3(0.04), albedo.rgb, metalness); // Діелектрик: F0 = 0.04 (поширене значення за замовчуванням для пластику/неметалу) // Метал: F0 = колір альбедо (металеве дзеркальне Є кольоровим) vec3 diffuseAlbedo = albedo.rgb * (1.0 - metalness); // Метал: немає дифузного (вільні електрони поглинають усе пропущене світло) // Діелектрик: дифузне = альбедо // Перцептивна шорсткість → α (для функцій D, G): float alpha = roughness * roughness; // «Перевідображення» Disney
Чому roughness²? Параметр перцептивної шорсткості підноситься до квадрата перед передачею у формулу GGX. Це перевідображення робить повзунок шорсткості лінійнішим на відчуття — без нього більшість варіації матеріалу втиснулася б у значення шорсткості 0–0,3, а діапазон 0,3–1,0 виглядав би однаково шорстким. Піднесення до квадрата рівномірніше розподіляє перцептивно важливий діапазон по повзунку.

6. Освітлення на основі зображень (IBL)

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

// Інтеграл по півсфері для IBL: Lₒ(N, V) = ∫_Ω f(ωᵢ, ωₒ) Lᵢ(ωᵢ) (N·ωᵢ) dωᵢ // Наближення розщепленої суми (Epic Games, Brian Karis 2013): // Інтеграл розщеплюється на дві попередньо обчислені частини: // Частина 1: Дифузна освітленість (член Ламберта) // Для кожного напрямку N: попередньо обчисли дифузний інтеграл // → Кубічна карта освітленості (найнижчий міп розмитої карти оточення або коефіцієнти SH) vec3 irradiance = texture(irradianceMap, N).rgb; vec3 diffuse = irradiance * albedo / PI; // Частина 2: Дзеркальна (розщеплюється на семпл оточення + BRDF LUT) // Попередньо відфільтруй карту оточення для кожного рівня шорсткості: // При roughness=0: різка карта оточення (міп 0) // При roughness=1: сильно розмита карта оточення (найвищий міп) vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_MIPS).rgb; // BRDF-таблиця інтегрування: 2D-текстура, індексована за (N·V, roughness) // зберігає (масштаб, зсув) для інтеграла члена Френеля vec2 brdfLUT = texture(brdfLUTTexture, vec2(max(dot(N, V), 0.0), roughness)).rg; // Об'єднай: vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); vec3 specular = prefilteredColor * (F * brdfLUT.x + brdfLUT.y); vec3 kS = F; vec3 kD = (1.0 - kS) * (1.0 - metalness); vec3 Lo = (kD * diffuse + specular) * ao;

Попередньо відфільтрована карта оточення та BRDF LUT обидві обчислюються один раз (або офлайн, або під час запуску застосунку з HDR-оточення). Це наближення розщепленої суми робить IBL придатним для реального часу, розділяючи дві половини вихідного інтеграла — одну, що залежить лише від оточення, та іншу, що залежить лише від BRDF — на текстури, які можна дешево семплювати у фрагментному шейдері.

7. Повний фрагментний шейдер PBR на GLSL

// Компактний PBR на GLSL (пряме освітлення, без IBL) // Вхідні дані: albedo, roughness, metalness, normal, дані про світло precision mediump float; uniform vec3 uAlbedo; uniform float uRoughness, uMetalness; uniform vec3 uLightPos, uLightColor, uCamPos; varying vec3 vWorldPos, vWorldNormal; const float PI = 3.14159265; float DistributionGGX(vec3 N, vec3 H, float rough) { float a = rough * rough; float a2 = a * a; float NdH = max(dot(N, H), 0.0); float d = NdH*NdH*(a2-1.0)+1.0; return a2 / (PI * d * d); } float GeometrySmith(float NdV, float NdL, float rough) { float k = (rough+1.0)*(rough+1.0)/8.0; float g1 = NdV / (NdV*(1.0-k)+k); float g2 = NdL / (NdL*(1.0-k)+k); return g1 * g2; } vec3 FresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0-F0) * pow(clamp(1.0-cosTheta, 0.0, 1.0), 5.0); } void main() { vec3 N = normalize(vWorldNormal); vec3 V = normalize(uCamPos - vWorldPos); vec3 L = normalize(uLightPos - vWorldPos); vec3 H = normalize(V + L); float NdV = max(dot(N, V), 0.0); float NdL = max(dot(N, L), 0.0); vec3 F0 = mix(vec3(0.04), uAlbedo, uMetalness); // Дзеркальне Кука-Торренса float D = DistributionGGX(N, H, uRoughness); float G = GeometrySmith(NdV, NdL, uRoughness); vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); vec3 specular = D * G * F / max(4.0 * NdV * NdL, 0.001); // Дифузне Ламберта vec3 kD = (vec3(1.0) - F) * (1.0 - uMetalness); vec3 diffuse = kD * uAlbedo / PI; // Підсумкова яскравість vec3 Lo = (diffuse + specular) * uLightColor * NdL; // Розсіяне (заглушка — замінити на IBL) vec3 ambient = vec3(0.03) * uAlbedo; // Тональне відображення + гамма-корекція vec3 color = Lo + ambient; color = color / (color + vec3(1.0)); // Тональне відображення Рейнхарда color = pow(color, vec3(1.0/2.2)); // лінійний → sRGB gl_FragColor = vec4(color, 1.0); }

8. Розширення: лак, підповерхневе розсіювання, анізотропія

Лак (покриття, автомобільна фарба)

Двошаровий BRDF для автомобільної фарби, лакованого дерева та подібних матеріалів. Шар лаку — це гладкий діелектричний шар (F0=0.04, roughness≈0.05) поверх шару базового матеріалу. Світло взаємодіє з обома шарами:

// Двошаровий BRDF лаку: brdf_clearcoat = clearcoatIntensity · D_GGX(H, α=0.001) · G · F_clearcoat Lo = (diffuse + specular_base) * (1 - F_clearcoat) + specular_clearcoat

Анізотропні відбиття (шліфований метал, волосся)

Шліфований метал та волосся мають мікроскопічні борозни вздовж одного напрямку, що змушує дзеркальний відблиск розтягуватися тангенціально, а не бути радіально симетричним. Анізотропні BRDF використовують окремі значення шорсткості вздовж напрямків дотичної (αT) та бідотичної (αB):

// Анізотропний NDF GGX (Burley 2012) D_aniso(H) = 1 / (π·αT·αB · ((T·H/αT)² + (B·H/αB)² + (N·H)²)²) // αT = шорсткість уздовж напрямку дотичної // αB = шорсткість уздовж бідотичної // Шліфований метал: αT=0.05 (гладко вздовж шліфування), αB=0.4 (шорстко впоперек)

Підповерхневе розсіювання (шкіра, віск, мармур)

Для напівпрозорих матеріалів світло входить у поверхню, відбивається всередині та виходить в іншій точці. Стандартне наближення реального часу — це підповерхневе розсіювання в екранному просторі (SSSSS): розмиття дифузного освітлення в екранному просторі гаусовим ядром, зваженим за товщиною матеріалу. Disney Principled BSDF включає спеціальний параметр підповерхні, що змішує дифузне Ламберта та підповерхневу модель Ганрагана-Крюгера.

PBR на практиці: робочий процес metalness/roughness тепер універсальний. І Unreal Engine (GGX + Сміт + Шлік), і Unity (те саме формулювання) використовують практично ідентичні реалізації BRDF. Ключові відмінності між рушіями полягають у тому, як вони опрацьовують IBL, якість фільтрації тіней та кількість підтримуваних шарів матеріалу, а не в основній математиці BRDF.

PBR змістив графіку від «виглядає добре» до «виглядає фізично правдоподібно незалежно від умов освітлення» — матеріал, створений за студійного освітлення в Substance Painter, просто працює під сонячним світлом надворі, у підземних печерах та неонових провулках без ручного підлаштування. Саме ця узгодженість, більше за будь-яку конкретну візуальну якість, — причина, чому PBR став універсальним.