Why Ray Tracing?
光栅化不太好去表示一些全局的效果。
地图大,整个地图渲染非常耗,质量较低。
Ray tracing is accurate, but is very slow
- Rasterization: real-time, ray tracing: offline
- ~10K CPU core hours to render one frame in production
Basic Ray-Tracing Algorithm
Light Rays
Three ideas about light rays
- Light travels in straight lines (though this is wrong)
- Light rays do not “collide” with each other if they cross (though this is still wrong)
- Light rays travel from the light sources to the eye (but the physics is invariant under path reversal - reciprocity). 光线的可逆性,可以认为眼镜发出感知的光线,最后打到光源。
“And if you gaze long into an abyss, the abyss also gazes into you.” — Friedrich Wilhelm Nietzsche (translated)
虽然是错的,但可以这么理解。从相机(我们的眼镜)出发,往世界中投放光线,光线在弹来弹去之后到达光源。(光追中“追踪”的意思)
Ray Casting
Appel 1968 - Ray casting
- Generate an image by casting one ray per pixel
- Check for shadows by sending a ray to the light
假设眼镜是一个点,光源也是点光源。对于场景中的物体,光线打到它之后会发生完美的折射或反射。只考虑光线打到的最近的物体,这样解决了深度测试的问题。
eye ray 打到点之后,要考虑这个点会不会被照亮,往光源连线(shadow ray),如果中间没有物体阻挡,说明光源可以照亮这个点。如果有东西挡着,说明点在阴影里。有了法线,有了入射方向和出射方向,就可以开始着色。着色完就可以在 Image plane 写入像素的值。
这里说的是光线只弹射一次。弹射多次要参考下面的 Recursive (Whitted-Style) Ray Tracing
Recursive (Whitted-Style) Ray Tracing
眼镜投射光线打到一个点的时候,如果是个玻璃材质,应该要做个镜面反射。
玻璃球还可以折射打到另外的点,再折射出来。
如果这个点,由于光线的弹射次数多了,在每一个弹射的点都会计算着色的值。(四条虚线)看光源是否能照亮到点。
如果光源能够照亮弹射的点,就把所有弹射点(光路,折射也算)着色的值都加到 image plane 对应的像素中。同时也考虑能量的问题,例如反射占了能量60%,折射能量占了40%。
对于不同类型的光线,眼镜直接打到的光线称为 primary ray,在一次弹射之后的光线称为 secondary rays,与光源连线判断可见性的叫 shadow ray。
还有很多技术问题:
- 怎么判定光线被遮挡
- 怎么判断光线投射出去会打到哪里
- 怎么求反射光和折射光的方向,以及各自带的能量
- 衰减怎么算
Ray-Surface Intersection 求光线和表面的交点
光线在数学上就是射线,有起点和方向。对于任何一个点,都可以用上图中的公式来表示。
光线怎么和球做交点?
求公式中的 t,求传播多久可以打到球。
t 要满足物理上的意义,是正的。解出来的根也要有物理意义,解出来不能是虚数,而是实数。
我们还能将其推广到光线与隐式表面的求交:
同样可以求出不为虚数,不为负数的 t 值。
对于显式表面:
Why?
- Rendering: visibility, shadows, lighting …
- Geometry: inside/outside test
- 随便取一个点,从其发射光线(射线),如果与模型有奇数个交点,那么一定在物体内。偶数在物体外。(3D也一样,物体必须封闭)
How to compute?
Let’s break this down:
- Simple idea: just intersect ray with each triangle
- 一个一个三角形求是否和光线有交点
- Simple, but slow (acceleration?)
- Note: can have 0, 1 intersections (ignoring multiple intersections) 很少考虑平行情况
怎么样求光线与三角形的交点:
三角形在平面内,可以把问题分解成两个问题:
- 光线和平面怎么求交
- 找到交点之后判定点是否在三角形内。
怎么和光线求交?
平面的定义
平面可以由一个法线和一个点定义,那么平面上所有的点都可以通过法线和点,用上图的公式来表示。
有没有办法一步求出来光线和三角形的交点?
答案就是:
Möller Trumbore Algorithm
A faster approach, giving barycentric coordinate directly
只要三个系数加起来等于1,就可以得到任意一个在三个点定义的三角形所定义的平面内的点
由于矢量是三维的,所以下面的等式就等于三个式子,三个未知量都可以求出来,利用克莱姆法则解线性方程组。
合理的解:t是正数、点在三角形内,也就是重心坐标的系数都要是非负的(1-b1-b2,b1,b2)。
把光线和每个三角形都做一次求交,再找出最近的交点(t 最小),但是这样很慢。
如何提升速度?
Ray Tracing – Performance Challenges
Simple ray-scene intersection
- Exhaustively test ray-intersection with every triangle
- Find the closest hit (i.e. minimum t)
Problem:
- Naive algorithm = #pixels ⨉ # triangles (⨉ #bounces)
- Very slow!
For generality, we use the term objects instead of triangles later (but doesn’t necessarily mean entire objects)
上图如果用原始的方法,那每一根光线都要和 10.7M 的三角形求交,再乘以像素数,有玻璃,光线可能也不止弹射一次。