GAMES101 Lec 13~14(1):Ray Tracing(1) Whitted风格光线追踪

1 引入——Shadow Mapping 阴影贴图
之前提到光栅化的着色,我们知道这是一种局部的现象
着色的过程中,我们只会考虑着色点自己,光源,以及摄像机
我们不考虑其他物体,甚至不考虑物资自身的其他部分对着色点的影响
而事实上是会有遮挡的关系的,是会有阴影的
之前我们解决不了阴影问题,现在来试着在光栅化的范围里面解决一下

一种解决方法即为Shadow Mapping

在这里插入图片描述

本质上Shadow Mapping这个方法是一种图像空间的做法,也就是在生成阴影这一步,我们不需要知道场景的几何信息(会在之后的实现步骤中讲述)
同时这个方法也会产生走样问题,并且经典的Shadow Mapping只能处理点光源(接下来也会以点光源为例进行讲解)
这个方法的关键思想在于——如果有点不在阴影里,那么这个点可以被摄像机和光源都看到
从这个思想我们看出阴影应该会有很明显的边界,也就是硬阴影

在这里插入图片描述 

1.1 阴影贴图原理

  • 首先我们从光源看向场景,做一遍光栅化,我们就会得到光源能看到什么,得到一幅图在这里插入图片描述

    我们不进行着色,把这个图的深度记下来
    在这里插入图片描述
  • 我们从摄像机出发,再次看向这个场景在这里插入图片描述
  • 我们把现在看到的点,投影回光源刚才看到的投影平面上
    然后把 现在看到的点 和 投影回去光源得到的位置 这两个进行深度比较
    如果深度一致,那就可以被看到
    在这里插入图片描述

    如果深度不一致,那就看不到
    在这里插入图片描述


    下面举例
    我们做Shadow Mapping的一个结果

    在这里插入图片描述

     从光源视角看到的图,以及深度
    在这里插入图片描述

在这里插入图片描述 

从相机看过去,做完测试的结果
看着很脏,为什么呢?这也是这个方法存在的问题之一
浮点数的相等比较存在精度问题
人们处理精度的方法很多,但是都不能本质解决问题
还有一个问题是,一开始我们从光源看向场景,我们要把它存到一个图里面
这个图本身存在分辨率,它与渲染时的分辨率的搭配不好的话,会存在走样
更大的深度图的分辨率,开销也会变大
在这里插入图片描述

即使存在问题,依然是目前的主流方法在这里插入图片描述 

1.2 存在的问题

  • 总结一下提到的问题
    硬阴影(点光源)
    阴影图的分辨率
    浮点数的比较
    所以从光栅化的思想去做全局的现象,是比较困难的事情在这里插入图片描述

关于软硬阴影的问题
其实就是本影与半影的关系
如果有软阴影,一定是因为光源有一定的大小在这里插入图片描述 

2 Why Ray Tracing?

  • 光栅化不好做全局的效果
    比如软阴影,光泽反射,间接光照
    有一些巧妙的方法可以处理,但是不能保证正确性在这里插入图片描述

光栅化很快速,但是质量不高在这里插入图片描述 

 光线追踪是很准确的,但是会比较慢
光栅化很容易做到实时,光线追踪经常做离线的应用
在这里插入图片描述

3 基本光线跟踪算法

3.1 光线定义

  • 我们首先需要对光线定义
    光沿直线传播,不发生碰撞,是从光源到人眼的
    对于第三个性质,我们在根据光路可逆性,应用时会采取从人眼到光源的方法在这里插入图片描述

3.2 Ray Casting 光线投射
光线追踪既然是追踪,我们会从终点开始,也就是从眼睛/相机开始
我们首先需要做的是光线投射

我们假设往虚拟的世界中看,眼前放了一个成像平面,成像平面被我们画成不同的像素格子
对于每一个像素,我们可以从相机连一条线,穿过这个像素,这样就可以打出一根光线,可以打到场景中
如果光线和场景的某一物体相交,那么交点和光源连线,看光源是否可见这个点(这个点在不在阴影里),如果可见,那么就形成一条有效的光路
那么就可以计算这条光路上的能量,进行着色在这里插入图片描述

在下面的例子中,我们永远考虑眼睛是一个针孔摄像机,即眼睛是一个点,一个位置,不考虑实际相机的处理,以及镜头什么的(这部分会在路径追踪说)
对于场景中的物体,我们假设光打到它之后会发生完美的折射与反射
下图从眼睛开始,穿过成像平面的一个像素,投射一条光线(eye ray)
这个光线会打到场景的某一个位置上,我们取最近的交点
(这一步其实就解决了深度测试的问题)

在这里插入图片描述

当我们发现了一个点之后,我们要考虑这个点会不会被照亮
我们从这点到光源连一条线(shadow ray)
如果可以连上就表示能被照亮(下图黑线箭头为法线)
有了法线,入射方向,出射方向,我们就可以做着色,写入像素的值,这时候可以用各种各样的着色模型 比如之前的Blinn Phong在这里插入图片描述 

光线投射做了这么一件事,每一个像素投出去一个光线,和场景相交求的话求最近交点,最近交点和光源连线,判定是否可见,然后算着色,写回像素的值
3.3 递归(Whitted风格)光线追踪 
之前就是用光线投射的方法,我们还是只考虑光线弹射一次,但其实光线可以弹射很多次,这也就是接下来要介绍的这个方法能做的
在这里插入图片描述

我们还是从光线投射开始 
在这里插入图片描述

在这个点上,我们先考虑这个球是一个玻璃球
光线打到这个球上肯定发生两个事情,一个是要被反射掉,一个是被折射进去
在这里插入图片描述 

在这里插入图片描述 

在算着色的过程中也发生了一点变化
之前是光线投射到这个点之后,看这个点能不能被照亮,然后再计算它的着色
在光线弹射次数多了以后,我们在每一个弹射点都会去计算着色的值(能量损失什么也要算),然后把它们都加回这个像素的值里面去 在这里插入图片描述

4 光线与物体相交

4.1 光线与隐式表面相交

我们要判断光线投射出去之后要打到什么,也就是要求交点
那么求交点之前我们先把数学上的光线定义出来

  • 光线定义也就是一条射线,有一个起点,有一个方向,有这两个量就可以定义一条光线
    光线上的任何一个点都可以用 t 为自变量的函数表示
    在这里插入图片描述

为了说明光线与曲面的交点
我们从光线与球求交的情况开始切入,交点即这个点又在球上又在光线上
方程于是可以建立起来了 
在这里插入图片描述

解这个方程可以有很多方法,我们根据解的情况可以得到位置关系
在这里插入图片描述 我们拓展到一般性的隐式表面,方法都是一样的 
在这里插入图片描述

 4.2 光线与显式表面求交
对于显式表面的渲染,光线如何与三角形求交是一个很重要的话题
在几何上,通过这个办法也可以判断一个点在不在物体内(点如果在封闭形状内,向外打一条光线,得到的交点数量一定是奇数)
话题回到光线与三角形求交
在下图的小奶牛中,判断光线是否与它相交
最最简单的做法就是把它的三角形面挨个判断一遍(每个三角形面都会有0个或者1个交点)
很直观但是很慢(之后会介绍加速方法)

在这里插入图片描述

怎么样做三角形和光线的交点呢?
三角形肯定在一个平面内,所以问题可以被分成两部分
光线是否和平面有交点
这个交点在不在三角形内部
在这里插入图片描述 

平面的定义采用点法式的定义方式
-即用一个平面上的点与平面上的法线,利用点乘为0的方式建立平面方程 
在这里插入图片描述

 我们把光线方程带入平面方程,解出来光线与平面的交点
再之后可以判断在不在三角形内部
在这里插入图片描述

 但是人们想两步合成一步,也就是下面的方法
左边是光线上的点,右边是用重心坐标表示的三角形内的点
解法如下图
解出来之后要判断是否合理,首先 t 得是正的,并且b1 b2 b3都是非负的
在这里插入图片描述

5 轴对齐包围盒(AABB)的求交

  • 我们与每一个三角形求交,可以找到最近的交点
    但是 计算次数 = 像素数×三角形数×弹射数 这样太慢了
    所以我们要对这个过程进行改进加速,方法之一是包围盒
    在这里插入图片描述

 包围盒的思想是,将一个复杂的物体,用简单的形状围起来,保证物体一定在这个简单的形状之内
如果光线连包围盒都碰不到,那肯定碰不到包围盒里的物体在这里插入图片描述

对于三维的形状,我们最常用的是长方体——不同的三对对面形成的形状
这也是AABB——轴对齐包围盒
所谓轴对齐,也就是长方体的任何一个轴都是沿着坐标轴的在这里插入图片描述 

接下来我们考虑光线与包围盒的求交
我们先从二维的角度(由不同的两对对面形成)考虑,三维可以同理得到
对于给定的一个光线
我们可以分别求出它与竖直和水平面的交点(此时t可能会有正负)
我们取min里的max,max里的min,
于是得到了进入和出去包围盒的 t 的值在这里插入图片描述 

从三维的情况来说的话
只有光线都进入了三组对面,才能说光线进入了这个盒子
只要光线离开任意一对对面,就离开了这个盒子
我们对三组对面都计算一次 t
取min中的max为最后进入时间,max中的min为最早出去的时间
进入小于出去时,也就代表光线在它们之间是在盒子里的在这里插入图片描述 

光线不是直线,是射线
所以有交点的情况下,我们需要对 t 进行检查
盒子在光线背后——出去时间是负数
光线起点在盒子内部——出去时间是负数且进入为正数
进行总结,在AABB的情况下
iff(if and only if)进出t小于出去t且进入t为正数
此时才有交点在这里插入图片描述 

为什么我们要用轴对齐包围盒?
因为轴对齐的情况下,我们可以在求t的时候,只用某一轴的信息,不用整个坐标,比点乘计算会更容易一点在这里插入图片描述 

6 使用轴对齐包围盒加速光线追踪

如果场景非常复杂,我们会先找到包围盒,然后再根据包围盒的情况进行对物体的求交
找到包围盒的过程是空间划分的过程

6.1 均匀空间划分

  • 首先我们找到一个场景的包围盒在这里插入图片描述

然后对这个包围盒进行划分,分成一堆格子在这里插入图片描述 接着判定与物体相交的格子 
在这里插入图片描述

做完以上预处理之后,我们得到了可能含有物体的格子
在接下来做光线追踪的过程中,我们只要判断光线有交到的是不是有物体的格子,不是的话直接跳过,是的话再对盒子里的物体求交
(此处假设光线与物体求交很慢,与盒子求交很快)
下图一条光线沿着右上打过去,我们怎么知道它会碰到哪个盒子呢
最简单的想法是,如果是右上,那么下一个盒子一定在右边或者上边(这也是之前光栅化没提到的话题,如何光栅化一条线)
在这里插入图片描述

 

所谓加速就是多做光线与盒子求交,少做光线与物体求交,那么加速效果怎么样呢
如果划分成1×1的格子,那么没有加速效果 在这里插入图片描述

如果划分太密集,效率也不高 
在这里插入图片描述

 根据经验,人们大概得出划分成场景中物体数目的27倍的格子数比较好
在这里插入图片描述
格子的划分方法在大量均匀分布的物体上比较有效 
在这里插入图片描述

然而在复杂空旷的场景中表现不好,会出现类似体育场中找茶壶的现象在这里插入图片描述 

6.2 空间划分

在格子法中,空间划分的都是大小相同的格子,然而有些空旷的地方不需要这样,太浪费了,我们想在没物体的地方用大盒子,有物体的地方用密集的盒子
这也就引出了空间划分的方法在这里插入图片描述

左一是八叉树划分,先把三维空间切成八份(二维的话如图是四份),对于每一个子节点,再切一遍,以此类推
如何停止呢,我们可以定个类似这样的规则,比如二维的情况,切成四块时三块都没物体,就不在往下切 之类的,其思想也就是划分到一定程度还没物体就不切了
但是人们不喜欢八叉树,因为比如在二维这种划分方法是四叉树,三维是八叉树,那么维度更高,就是2的n次方叉树,这样并不好,维度更高会越来越复杂
为了解决这个问题,能让空间得到划分并且和维度无关,人们发明了KD树
KD树和八叉树的划分方法几乎完全相同,只不过它每次沿着某一个轴看开,并且只砍一刀,永远这么做
空间被划分成类似二叉树的结果,每次节点的划分底下都只有两个子节点
划分时为了均匀起见,xyz依次砍
还有很多方法,比如BSP树,是一种对空间二分的划分方法,它每次选一个方向砍开,它和KD树的区别是它不是横平竖直地砍,而且它会有越高维越不好计算的问题(砍开二维用线,砍开三维用面,维度越高越复杂)

6.2.1 KD树

以下是一个KD树划分的例子
我们先明确,这些空间划分方法是在光线追踪之前,先把空间加速结构划分好,然后再进行光线追踪
下图每一块都需要砍开,只不过示意图只沿着右边在做

  • 一开始竖直划分成1 B
    之后B划分成2 C
    以此类推在这里插入图片描述

当前节点沿着哪个轴划分
划分在哪里
中间节点一定有子节点
最终的物体存在叶子节点上在这里插入图片描述 

下面我们看看这个结构将如何加速光线追踪

  • 考虑我们划分成这种情况
    在这里插入图片描述

首先考虑最大的包围盒A,发现有交点,那么对于左右子节点可能都有交集在这里插入图片描述 

我们发现和左边蓝色的有交点
我们假设它是叶子节点,就先这样,继续看右边,发现也有交点在这里插入图片描述 

在这里插入图片描述 

以此类推判断2 然后判断C (图略)
然后判断3,发现3是叶子节点,在3中与物体求交,找到交点在这里插入图片描述 

KD树会产生一些问题

  • 给出一个节点的包围盒,我们要知道它和哪些三角形有交集,这是很难的,不太好写
  • 一个物体和很多包围盒都有交集的话,它可能会存在很多个叶子节点中

    6.3 物体划分&BVH

    空间划分存在一些问题,于是人们发现了另一种做法,我们不从空间划分,我们从物体开始划分,这种划分形成的加速结构也就是所谓的BVH

  • BVH是怎么运作的呢,最开始也一样有一个盒子包围场景作为根节点在这里插入图片描述

 然后我们把物体分为两部分(怎么求之后再说),然后重新求他们这两部分的包围盒在这里插入图片描述

以蓝色节点为例,我们继续划分再重新求包围盒,划分到比较少的三角形,比如5个三角形左右就可以停止在这里插入图片描述 

 BVH的特性是,一个物体可以指存在在一个节点里,并且不用算三角形和包围盒求交了
但是BVH的划分并没有划分开,包围盒可能会相交,不过没什么问题,我们做到尽可能重叠少就好,这也是当今一个研究的方向
下图进行了一个总结
在这里插入图片描述

关于怎么划分一个节点,有很多方法
比如 选一个最长的轴划分 或者 取中间的物体(第n/2个三角形)(可以采用快速划分算法)
主要是为了保证树的平衡在这里插入图片描述 

关于BVH的存储结构也做一个总结,只有子节点存物体 

 在这里插入图片描述

 如何加速光线追踪和KD树其实差不多,到子节点测物体在这里插入图片描述

 一个是对空间的划分,一个是对物体的划分,以下是总结
在这里插入图片描述

到这里我们算是讲完了whitted风格的光线追踪。 

猜你喜欢

转载自blog.csdn.net/jiuzhouhi/article/details/123189708