高级 #graphics#ray-tracing

光线追踪基础

光线追踪(Ray Tracing)模拟光线的传播路径——从相机发射光线,弹射到场景中,计算光照贡献。相比光栅化,它能更真实地处理反射、折射和全局光照

🔦 逆向思考——不是”光从光源出发”,而是”光线从相机出发”

现实中,光线从光源发出,在物体之间反射,最终进入人眼。模拟这个过程——但 99.9% 的光线永远到不了人眼,计算浪费了。

光线追踪(Ray Tracing) 反过来:从相机(人眼)通过每个像素发射光线——只在需要时追踪。

传统光栅化:          光线追踪:
"这个三角形在哪个像素"  "这个像素看到的是什么"
逐个三角形处理         逐个像素追踪光线

🎯 Whitted 风格光线追踪

对屏幕上的每个像素

1. 从相机经过像素发射一条光线
2. 光线和场景中所有物体求交 → 找到最近的交点
3. 在交点计算直接光照(光源→交点→相机)
4. 如果交点是光滑表面 → 递归发射反射光线
5. 如果交点是透明物体 → 递归发射折射光线
6. 累加所有光照贡献 → 像素颜色
def trace(ray, scene, depth=0):
    if depth > max_depth:
        return black
    
    hit = scene.intersect(ray)
    if not hit:
        return background_color
    
    # 直接光照
    color = direct_light(hit.point, hit.normal, scene)
    
    # 反射
    reflect_ray = reflect(ray.direction, hit.normal)
    color += 0.5 * trace(reflect_ray, scene, depth+1)
    
    # 折射(如果是透明物体)
    if hit.material.transparent:
        refract_ray = refract(ray.direction, hit.normal)
        color += 0.5 * trace(refract_ray, scene, depth+1)
    
    return color

为什么光线追踪比光栅化更真实?

光栅化:直接光照 + 静态阴影
光线追踪:反射 + 折射 + 间接光照 + 软阴影 + ...

一个镜面球体反射出周围环境——光栅化很难做到,光线追踪自然支持。

📐 光线与物体求交

最简单的形状——球体:

P(t) = O + t·D    — 光线的参数方程(O=起点,D=方向)

球体:|P - C|² = r²    — 所有到球心距离为 r 的点

代入求解 t:二次方程 at² + bt + c = 0
解 → t > 0 的最小值 → 最近的交点
def ray_intersect_sphere(ray_origin, ray_dir, sphere):
    oc = ray_origin - sphere.center
    a = dot(ray_dir, ray_dir)
    b = 2 * dot(oc, ray_dir)
    c = dot(oc, oc) - sphere.radius ** 2
    discriminant = b*b - 4*a*c
    if discriminant < 0:
        return None  # 不相交
    t = (-b - sqrt(discriminant)) / (2*a)
    return t if t > 0 else None

复杂形状(三角形网格)的求交需要加速结构——下一节讲。


🌍 路径追踪——渲染方程的求解

Whitted 风格只追踪反射/折射——但现实世界的光线更复杂:

  • 磨砂表面:光线向所有方向反射
  • 间接光照:光照到红色墙壁 → 墙壁反射红光 → 照亮附近白色物体 → 白色物体带了红色

路径追踪(Path Tracing) 用蒙特卡洛方法——每条光线在交点随机选择一个方向继续追踪,大量光线取平均:

每个像素发射 N 条光线:
  每条光线在每次弹射时随机选择方向
  最终累加所有弹射的贡献


取平均 → 近似真实光照

N 越大 → 噪声越少 → 结果越真实(但需要更多计算)
这就是为什么电影渲染一帧要几小时——而游戏追求实时必须用光栅化

📝 小结

概念一句话
光线追踪从相机发射光线模拟光路——反射/折射/间接光照
Whitted 风格递归追踪反射和折射光线
路径追踪随机方向追踪——蒙特卡洛方法求解渲染方程
vs 光栅化光线追踪更真实,光栅化更快(实时)

为什么先学这个? 光线追踪需要大量求交计算——需要加速结构(BVH, KD-Tree)