ГоловнаСтаттіРендеринг

Відстеження шляхів: Рівняння рендерингу, Монте Карло та «Російська рулетка»,

Як моделювання випадкового відбиття фотонів — замість ручної реалізації ефектів освітлення — дозволяє отримати м’які тіні, розливи кольорів та каустики безкоштовно.

mysimulator teamОновлено — червень 2026≈ 11 хв читання▶ Відкрити симуляцію

Один интеграл описывает весь транспорт света

Растеризация — техника, используемая в реальном времени, быстро рисует треугольники и имитирует освещение с помощью набора отдельных трюков: тени, окружающее затенение, пробоики освещения, отражения пространства экрана, каждый из которых решает одну узкую проблему. Path tracing использует совершенно другой подход: он напрямую оценивает физическое уравнение, которое определяет, как свет распространяется по сцене, впервые формализованное Джеймсом Каджией в 1986 году как уравнение рендеринга.

L_o(x, ω_o) = L_e(x, ω_o) + ∫_Ω f_r(x, ω_i→ω_o) · L_i(x, ω_i) · (ω_i · n̂) dω_i L_e = излучение поверхности f_r = BRDF (как поверхность рассеивает свет) L_i(x, ω_i) = L_o(x', −ω_i) — рекурсивный: входящий свет является исходящим в другом месте ω_i · n̂ = cos θ_i, литомерный косинус; Ω = сфера над поверхностью Поскольку L_i справа зависит от L_o в другой точке, уравнение рекурсивное — если его развернуть, это бесконечное суммирование путей любой длины: прямой свет, один отраженный луч, два отраженных луча и т.д. Каждый визуальный эффект, который может захотеть рендерер — мягкие тени, кровоточивость цвета, коаустики — уже содержится в этом одном интеграле. Главный вызов path tracing заключается в его эффективной оценке.

L_o(x, ω_o) = L_e(x, ω_o) + ∫_Ω f_r(x, ω_i→ω_o) · L_i(x, ω_i) · (ω_i · n̂) dω_i

L_e = the surface's own emission        f_r = the BRDF (how the surface scatters light)
L_i(x, ω_i) = L_o(x', −ω_i)             — recursive: incoming light IS outgoing light elsewhere
ω_i · n̂ = cos θ_i, the Lambertian cosine term; Ω = the hemisphere above the surface

Estimating an integral by rolling dice

The hemisphere integral has no closed form for an arbitrary scene, so it is approximated with Monte Carlo integration: draw N random directions, evaluate the integrand at each, and average.

∫ f(x) dx ≈ (1/N) Σ f(xᵢ) / p(xᵢ) xᵢ drawn from probability density p

Unbiased: E[estimate] = the true integral, for any N

Standard deviation ∝ 1/√N → 4x more samples only halves the visible noise

That 1/√N convergence is the defining constraint of the whole field: it is why a freshly started path-traced render looks grainy and only slowly cleans up, and why so much research effort goes into either reducing variance per sample (importance sampling, next event estimation) or denoising the result rather than brute-forcing more samples.

∫ f(x) dx ≈ (1/N) Σ f(xᵢ) / p(xᵢ)      xᵢ drawn from probability density p
Unbiased: E[estimate] = the true integral, for any N
Standard deviation ∝ 1/√N  →  4x more samples only halves the visible noise

Calculating Light Scattering: The Importance of BRDF

The f_r term — the BRDF (Bidirectional Reflectance Distribution Function) — describes a material. A perfectly matte (Lambertian) surface has the simplest possible BRDF, f_r = albedo/π, scattering incoming light equally in every direction. Real materials — brushed metal, plastic, skin — are usually modelled with a microfacet BRDF such as GGX, which treats the surface as a statistical field of tiny mirrors and combines a normal distribution function, a geometric shadow-masking term and Fresnel reflectance into one physically-grounded reflection lobe ranging continuously from a sharp mirror to a soft, glossy highlight.

жива демонстрація · пов'язана симуляція● LIVE

Відстеження одного шляху від камери

Основний цикл стріляє промінь від камери, відбиває його від того, що він вдаряє об нього відповідно до BRDF поверхні, і накопичує випромінене світло вздовж шляху, зважене на коефіцієнт проходження, який відстежує, скільки початкового світла виживає після кожного відбиття:

tracePath(ray, maxDepth = 8): throughput = 1; radiance = 0 for depth in 0..maxDepth: hit = scene.intersect(ray); if !hit: break radiance += throughput * hit.material.emission (wi, pdf, brdfVal) = hit.material.sample(hit.normal, ray.dir) throughput *= brdfVal * cos(hit.normal, wi) / pdf // BRDF * cosine / pdf ray = { origin: hit.point, dir: wi } return radiance Вибір wi рівномірно по всій півсфери було б марним використанням більшості зразків у напрямках, які мало сприяють. Важливе семплювання замість цього витягує wi з розподілу, що має форму інтеграла — для Lambertian поверхні, семплювання півсфери з вагою косинуса обирає напрямки пропорційно cos θ, який зручно скасовує косинусний член в оновленні проходження повністю.

tracePath(ray, maxDepth = 8):
  throughput = 1;  radiance = 0
  for depth in 0..maxDepth:
    hit = scene.intersect(ray);  if !hit: break
    radiance += throughput * hit.material.emission
    (wi, pdf, brdfVal) = hit.material.sample(hit.normal, ray.dir)
    throughput *= brdfVal * cos(hit.normal, wi) / pdf     // BRDF * cosine / pdf
    ray = { origin: hit.point, dir: wi }
  return radiance

Stopping without bias: Russian roulette

Capping path length at a fixed depth is simple but introduces systematic bias — long light paths (through glass into a bright light, say) are cut off every time and their contribution is lost entirely. Russian roulette terminates a path randomly instead, with survival probability q — often the luminance of the current throughput — and rescales any surviving path by 1/q. Because E[(throughput/q) · q] = throughput, the estimator stays unbiased even though most individual paths are cut short, which lets a renderer bound its worst-case cost without systematically darkening the image.

Frequently asked questions

Чому трасування шляхів генерує шумні зображення при низькій кількості зразків?

Трасування шляхів оцінює інтеграл рендерингової рівняння за допомогою випадкових Монте-Карлових семплів, і стандартне відхилення цієї оцінки падає пропорційно до 1/√N. Подвоєння кількості зразків на піксель лише вдвічі зменшує шум, тому для отримання зваженого зображення зазвичай потрібно сотні або тисячі зразків, якщо не використовувати шумозаглушення або більш розумний метод семплювання.

Що таке «російська рулетка» і чому вона не спотворює результат?

«Російська рулетка» випадково обрізає світловий шлях з ймовірністю 1−q, а масштабує внесок вижилого шляху на 1/q. Оскільки очікуване значення (внесок/q) × q дорівнює початковому внеску, оцінювач залишається незміненим у середньому, навіть якщо окремі шляхи обрізаються — що дозволяє рендереру обмежити довжину шляху без систематичного затемнення зображення.

Чому трасування шляхів отримує глобальне освітлення та м'які тіні безкоштовно?

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

Спробуйте наживо

Усе, що вище, працює прямо у вашому браузері — відкрийте the simulation і змінюйте параметри під час роботи. Нічого не встановлюється, нічого не завантажується на сервер, уся модель живе в одній вкладці.

▶ Відкрити симуляцію the simulation

Що ви знайшли?

Додати кроки відтворення (опційно)