Компьютерная графика
Ray Tracing: основы
В 1980 году Тёрнер Уиттед рендерил стеклянный шар 74 минуты. В 2023 году NVIDIA RTX 4090 рендерит ту же сцену за наносекунды - ускорение в 2.6 триллиона раз за 43 года. Идея та же: луч из камеры, пересечение с геометрией, рекурсивные вторичные лучи. Понимание базовых алгоритмов ray tracing - это понимание того, как работают Blender Cycles, Unreal Lumen, Disney's Hyperion renderer и каждая RTX-игра.
- **NVIDIA RTX (DXR/VK_RT):** аппаратные RT Cores реализуют BVH traversal и ray-triangle intersection. API: TraceRay() в HLSL, vkTraceRaysKHR в Vulkan
- **Blender Cycles / Disney Hyperion:** production ray/path tracers используют BVH с SAH, Embree (Intel) для CPU-трассировки, OptiX для GPU
- **Game engines (Unreal Lumen, RTX Remix):** гибридный подход: Whitted-style reflection/shadow rays + экранное пространство для диффузных эффектов
Пересечение луча с геометрией
В 1980 году Тёрнер Уиттед рендерил одно изображение 74 минуты на компьютере стоимостью 50 000 долларов. Сегодня NVIDIA RTX 4090 трассирует миллиарды лучей в секунду. Принцип неизменен: луч P(t) = O + t*D, где O - начало, D - направление. Пересечение луча с треугольником - базовая операция: алгоритм Молера-Трумбора решает систему уравнений P = O + t*D = (1-u-v)*V0 + u*V1 + v*V2 через матрицу Крамера за O(1). Проверяется: t > 0 (впереди), u >= 0, v >= 0, u+v <= 1 (внутри треугольника).
Алгоритм Молера-Трумбора (1997): det = cross(D, e2) dot e1; если |det| < eps - луч параллелен. u = cross(D, e2) dot (O-V0) / det; v = cross(O-V0, e1) dot D / det; t = cross(O-V0, e1) dot e2 / det. Где e1 = V1-V0, e2 = V2-V0. SIMD-векторизация: 8 лучей параллельно за цену одного.
Алгоритм Молера-Трумбора проверяет условие |det| < eps в начале. Что это условие означает физически?
BVH: иерархия ограничивающих объёмов
Сцена с 1 миллионом треугольников при наивном подходе: каждый луч проверяет 1 000 000 треугольников. При разрешении 1920x1080 и 100 лучах на пиксель - 207 триллионов проверок в кадр. BVH (Bounding Volume Hierarchy) решает задачу: треугольники группируются в иерархию ограничивающих прямоугольников (AABB). При трассировке луч сначала проверяет пересечение с AABB-узлом, и только при попадании - с дочерними узлами. Сложность: O(log n) против O(n). NVIDIA RTX реализует BVH аппаратно - специализированные RT cores.
Построение BVH: разбиение по оси с наибольшим разбросом (Surface Area Heuristic - SAH минимизирует ожидаемую стоимость запроса). AABB intersection тест: slab method - t_enter = max(t_x_min, t_y_min, t_z_min), t_exit = min(t_x_max, t_y_max, t_z_max), miss if t_enter > t_exit.
BVH сокращает время трассировки с O(n) до O(log n). При каком условии BVH деградирует до O(n)?
Рекурсивная трассировка: отражение и преломление
Рекурсивный ray tracing разворачивает оптику: луч ударяет о зеркальную поверхность и порождает отражённый луч, луч ударяет стекло - порождает преломлённый. Отражение: R = D - 2*(D dot N)*N. Преломление (закон Снеллиуса): n1*sin(theta1) = n2*sin(theta2). Рекурсия ограничивается максимальной глубиной (обычно 5-10) или весом луча (ниже порога - обрезать). Эффект Френеля: при скользящем угле даже стекло почти полностью отражает свет - коэффициент Шлика аппроксимирует эту зависимость.
Аппроксимация Шлика для коэффициента отражения: R(theta) = R0 + (1-R0)*(1-cos(theta))^5, где R0 = ((n1-n2)/(n1+n2))^2. При theta=0 (перпендикулярно) R=R0, при theta=90 (скользяще) R=1 (полное отражение). Используется в PBR-рендерерах повсеместно.
Полное внутреннее отражение (ТВО) происходит при преломлении. При каком условии луч не преломляется, а полностью отражается?
Модель Whitted: структура классического ray tracer
Уиттед (1980) описал первый практический рекурсивный ray tracer. Модель: для каждого пикселя испускается primary ray из камеры. При попадании вычисляется: (1) прямое освещение - shadow rays к источникам, (2) зеркальное отражение - рекурсивный отражённый луч, (3) преломление - рекурсивный преломлённый луч. Итого цвет = diffuse*phong + reflection + refraction. Whitted-style ray tracing корректно рендерит зеркала, стекло, чёткие тени, но не учитывает диффузные межотражения - для этого нужен path tracing.
Типичная структура рендера: 1 primary ray -> при попадании до 32 secondary rays (shadow + reflection + refraction + рекурсия). При разрешении 4K и 16 samples/pixel - 130 млрд лучей/кадр. RTX 3080 обрабатывает ~22 млрд лучей/с - недостаточно для real-time без денойзинга (DLSS/AI denoiser).
Ray tracing и path tracing - одно и то же, просто path tracing использует больше лучей
Whitted ray tracing трассирует детерминированные secondary rays (reflection, refraction). Path tracing случайно сэмплирует всю полусферу - это принципиально разные алгоритмы с разными гарантиями
Whitted RT: O(depth) лучей на пиксель, детерминированный, не конвергирует к физически корректному результату. Path tracing: O(samples) лучей, стохастический, конвергирует к уравнению рендеринга (rendering equation Kajiya 1986) при достаточном числе сэмплов.
Whitted ray tracing корректно рендерит зеркала и стекло, но не цветное кровотечение (color bleeding) - красный диффузный шар не окрашивает соседние поверхности. Почему?
Ключевые идеи
- **Молер-Трумбора:** O(1) пересечение луча с треугольником через барицентрические координаты. Базовая операция всего ray tracing.
- **BVH:** иерархия AABB сокращает сложность с O(n) до O(log n). NVIDIA реализует аппаратно в RT Cores.
- **Рекурсивная трассировка:** отражение R = D - 2*(D*N)*N, преломление по Снеллиусу, ТВО при n1 > n2. Шлик аппроксимирует Френеля.
- **Whitted vs Path Tracing:** Whitted - детерминированный, только specular. Path tracing - стохастический, конвергирует к физически корректному результату.
Связанные темы
Ray tracing объединяет модели освещения, теней и глобальной освещённости.
- Освещение: Phong, PBR — Direct illumination в Whitted RT использует те же модели освещения
- Тени и глобальное освещение — Shadow rays - часть Whitted RT; глобальное освещение требует path tracing
Вопросы для размышления
- BVH ускоряет трассировку с O(n) до O(log n), но требует O(n log n) времени на построение. При каких условиях стоит перестраивать BVH каждый кадр (динамические сцены), а когда - один раз при загрузке?
- RTX карты имеют специализированные RT Cores для BVH traversal. Почему эту операцию выгодно реализовывать аппаратно, а не на шейдерных ядрах? Что принципиально отличает BVH traversal от обычных GPU вычислений?
- Whitted RT рендерит зеркала идеально, но в природе не бывает идеально зеркальных поверхностей. Как PBR (roughness-metallic) материалы изменяют модель отражения? Что физически значит roughness > 0?