Ver Fonte

简述Whitted光线追踪

usuiforhe há 3 anos atrás
pai
commit
f6bb650658

BIN
图形学/Image/114.png


BIN
图形学/Image/115.png


BIN
图形学/Image/116.png


BIN
图形学/Image/117.png


BIN
图形学/Image/118.png


BIN
图形学/Image/119.png


BIN
图形学/Image/120.png


+ 125 - 0
图形学/图形学.md

@@ -1926,4 +1926,129 @@ Shadow Mapping可以处理硬阴影的情况:即一个点要么在阴影中,
 
 这里的光源(太阳)是有**体积**的,所以出现了 Penumbra 区域
 
+## Whitted-Style Ray Tracing
+
+> Whaitted风格的光线追踪
+
+光栅化无法表现一些全局的表现效果,包括:
+
+1. 软阴影(Soft Shadows)
+2. Glossy Reflection(物体本身有镜面反射,又带有粗糙的漫反射。环境中其他物体的光通过镜面反射到相机中)
+3. Indirect Illumination(间接光照,光通过了几次发射最后才发射到相机中,光栅化可以做但是效率和效果差)
+
+![](./Image/114.png)
+
+光线追踪一般用作离线计算,因为其计算量高,不能保证实时性,但是其质量高,符合物理规律的真实渲染结果
+
+在 **光线追踪** 中对于 **光线的定义**
+
+1. 光线是沿着直线传播的
+2. 光线和光线不会发生碰撞
+3. 光线从光源发射,在场景中通过反射,最终到达相机
+4. 光线的传播具有**可逆性**(reciprocity)
+
+做光线追踪实际上是从 眼睛/相机 出发,向世界中投射光线,然后 眼睛/相机 发出的光线在时间中不断反射,最终到达某个光源
+
+1. 从 眼睛/相机 发射射线,因为最后是渲染到一个平面上,平面具有像素点,那么相机到各个像素点就可以连成一条射线
+2. 当射线与某个物体相交,即表示从 眼睛/相机 看到了哪
+3. 再将相交点与光源做连线,判断该点是否在阴影中,如果不在阴影中则表示光源可以找到到,便可以得到 光源 -> 物体 -> 眼睛/相机 的光路
+4. 得到光路之后,通过计算可以得到最终的颜色
+
+- 假设 眼睛/相机 没有体积,是一个点
+- 假设 光源 是一个点光源
+- 假设 场景中的物体被光线打中之后 会发生完美的 反射/折射
+
+![](./Image/115.png)
+
+1. 从 眼睛中发出的光线 定义为 `eye ray` 也就是上图中蓝色的线
+2. 光线 理论上会穿过多个物体,但是只记录碰撞最近的点,从另一种层面上解决了深度测试问题(最近的点肯定会遮挡后面的点)
+3. 上图中 虚线 就是判断这个点会不会被光源照射到
+4. 上图中 黑色实线 就是法线
+5. 有了光源、入射方向、法线、出射方向就可以计算出这个点的颜色并写入到对应的像素点中
+
+虽然通过上述方法可以得到跟光栅化相似的结果, **但是** 这里的光线只弹射了一次,但是光线实际上可以弹射多次
+
+此处引入  Whitted-Style Ray Tracing(Whitted风格的光线追踪)
+
+> Whitted 是个人名  
+> 这个算法是个递归算法
+
+![](./Image/116.png)
+
+还是相同的情况,从 眼睛/相机 发射光线,假设 圆形 为玻璃球,光线经过玻璃球会发射折射
+
+那么 点1 就是第一个碰撞点,这个点发生了发射了一次**折射**和一次**反射**,使光线碰撞到了 点2 和 点3, 点3 又发生了一次**折射**和一次**反射**,通过这一次 折射 使得光线碰撞到了 点4
+
+点2、点3、点4对光线还可以做反射、折射,无线的做下去,Whitted-Style 做的就是将所有碰撞点都和光源做连线,计算**每个能被光源照亮点**的像素值,并且将所有计算出来的着色值**加到**那个对应的像素点上
+
+当然每个点的着色值不是直接加起来,而是每个点的值都有不同的权重,因为要考虑到 折射/反射 时的能量损失
+
+![](./Image/117.png)
+
+- 定义从 眼睛/相机 发出的光线为 `primary ray`
+- 定义从 反射/折射 的光线为 `secondary rays`
+- 定义从 碰撞点到光源的连线 为 `shadow rays`
+
+### 光线追踪的交点 (Ray-Surface Intersection)
+
+求光线和物体表面的交点
+
+数学中的光线就是一个射线,有一个起点,有一个方向
+
+假设起点坐标为 `o`, 方向向量为 `d`, 得到光线任一点的表达式 $ r(t) = o + t*d $ 其中 t 是 0 到 正无穷、
+
+对于 **隐式表面**
+
+假设现在要碰撞的是一个球,设球面上任意点的坐标为p,球心坐标为c,球的半径为R,得到球面的表达式 $(p - c)^2 - R^2 = 0$
+
+那么联立光线和球的表达式可以求出交点 $(o + td - c)^2 - R^2 = 0$
+
+![](./Image/118.png)
+
+> t 要大于0 并且 不可是虚数
+> 如果存在多个交点,取t较小值的交点,因为t越小离起点越近,t大的点会被t小的点挡住,没有使用意义
+
+可以将 光线 与 球 交点的计算,推广到其他 隐式表面 的计算上
+
+假设 隐式表面 的数学公式为 $ f(p) = 0 $, 带入 光线 的公式得到交点 $ f (o + t*d) = 0 $
+
+再 带入 上面说明的 t大于 0、 t不能为虚数、 多交点时取t小的点 就可以得到交点坐标
+
+对于 **显式表面**
+
+就是 光线 与 三角形 求交
+
+知道如何计算 光线与三角形 求交,可以 计算交点、是否在阴影中等
+
+通过计算还可以判断点是否在物体内部
+
+> 以 需要判断点 的位置为起点,向 任意方向 发射射线,如果交点个数是偶数则表示点在物体外,如果交点个数为奇数则表示点在物体内
+> 前提是 物体 一定得是封闭的
+
+那么计算 光线 与 三角形 求交呢?
+
+1. 先 计算 光线 与 三角形平面 的交点 (高中数学计算)
+2. 然后 判断 交点 是否在 三角形内 (直接用叉乘做就行)
+
+![](./Image/119.png)
+
+还有一个方法可以直接求出光线与三角形的交点,并且立刻判定交点是否在三角形内,那就是 `Moller Trumbore Algorithm`
+
+![](./Image/120.png)
+
+上图中 $P_0 P_1 P_2$ 分别是是三角形重心到三个顶点的向量
+
+通过 $ (1 - b_1 - b_2) * P_0 + b_1 * P_1 + b_2 * P_2 $ 可以表示三角形中任意点的坐标
+
+一个物体有很多个三角形,最简单暴力的做法就是交**依次对每个三角形求**,最后得出距离光线起点最近的点 也就是 t 最小的点
+
+### 加速计算光线与物体表面的求交 (Accelerating Ray-Surface Intersection)
+
+最暴力的做法,每个像素打出的光线都要与所有的物体,所有的三角形计算交点,并且光线每经过一次 反射/折射 都要计算新的光线与每个物体的三角形的交点
+
+如果真的是上面这种暴力做法,计算效率就特别低
+
+所以必须想办法提高渲染的效率
+
+
 # 动画模拟、仿真