光线追踪算法浅析(ZZ)

标签:
体育 |
分类: GPU |
http://blog.csdn.net/pizi0475/article/details/5640785 |
如果你看过精美的3D建筑效果图、复杂的好莱坞科幻片,你就会发现他们对玻璃材质、液体的渲染处理远远超越我们日常玩的3D游戏。这是因为他们都采用了光线追踪算法,相比3D游戏的光栅化算法有更真实的表现力。在3DS Max、Maya、Softimage XSI等软件中,无一例外地采用了基于光线追踪(Ray Tracing)和光能传递(Radiosity)的算法。由于光线追踪算法完全符合真实世界中光线的传播、折射、衍射、吸收等过程,所以可以渲染出肉眼无法分辨的3D场景。 随着CPU和GPU性能的爆炸性增长,在过去的几年里,已经有越来越多的公司试图实现实时光线追踪算法。 http://www.mcplive.cn/images/201001/20100122103745581.jpg |
|
和当今构建我们实时3D游戏中的光栅化技术不同,光线追踪技术能实现真正基于物理学的水面、倒影、折射等效果。但是光线追踪算法又无比复杂,大部分好莱坞大片渲染一帧就要拥有数千个CPU内核的渲染集群耗费十几个小时,要实现每秒30帧~60帧的实时光线追踪,谈何容易。早在2004年,德国青年Daniel
Pohl就通过修改《Quake 3》游戏,引入了光线追踪算法。通过这一翻天覆地的改变,修改版《Quake
3》所展现出的图形效果足以让当时大部分游戏汗颜。之后的几年里,Daniel Pohl更将注意力放到了《Quake 4》、《Quake
War》等游戏上,试图在这些游戏中实现实时光线追踪算法。有趣的是,Daniel
Pohl的实时光线追踪技术完全不依赖于GPU,仅仅是借助多内核CPU的运算能力“硬抗”。也许正因为如此,Daniel
Pohl随后被Intel高薪聘用,继续向实时光线追踪领域迈进。 在Intel披露Lar rabee显卡计划后,就有人惊呼,难道Intel希望用光线追踪代替日常实时3D计算中最基本最传统的光栅化算法,从而在根基上撼动NVIDIA、AMD的统治?2009年3月,一家名不见经传的公司—Caustic Graphics突然浮出水面,带来了一种具有突破性意义的实时光线追踪软硬件解决方案。这家由苹果公司图形部门三大元老创办的公司,声称一举解决了光线追踪算法效率低下的难题。究竟未来实时3D的世界,光线追踪和传统光栅化算法谁主沉浮?我们一起从原理入手,来了解什么是光线追踪。 |
|
在真实世界里,光线投射到物体表面的时候,会出现三种情况。这就是光线的吸收、反射、折射。光线被反射到不同地方被选择性地吸收后,光谱就会随之改变。经过多次的折射和反射,光线就会进入我们的眼睛,然后被我们感知。光线追踪技术就是要计算出光线发出后经过一系列衰减再进入人眼时的情况。 http://www.mcplive.cn/images/201001/20100122103835111.jpg |
|
|
http://www.mcplive.cn/images/201001/20100122103856800.jpg |
http://www.mcplive.cn/images/201001/2010012210394383.jpg |
|
|
在大部分赛车游戏中为了实现近距离车身的反光而不穿帮,大多使用了动态立方贴图(Dynamic Cube Map)技术。立方贴图技术允许开发者将场景视点和玩家观察角度保持一致,然后再重新渲染画面,把渲染结果保存下来供渲染使用。立方贴图虽然看上去不容易穿帮,但仔细观察你就会发现问题。自然界中的光线总是会存在不断的相互反射,例如上图中,使用立方贴图技术实现的茶壶,虽然很好地反射出了飞机,但却无法在茶壶口上出现飞机的反射画面。在现实世界中,不仅仅是光滑的茶壶壁上会反射出飞机,在茶壶口上依然会出现飞机的倒影。 http://www.mcplive.cn/images/201001/20100122104013381.jpg |
如果用光线追踪来实现各种反射效果会怎么样?根据我们上面介绍的光线追踪特性,这个技术可以用算法控制整个3D场景中的所有反射效果。在光线追踪计算中,所有的反射效果都能被计算在内,就连漫反射和多次反射都不会漏掉。以下方汽车渲染图为例,这辆布加迪车身的反射不仅相当真实,就连赛车背后的玻璃表面的反光也和现实世界完全吻合,如果使用光栅化算法要实现这样的效果,开发者的工作量简直难以想象。 http://www.mcplive.cn/images/201001/20100122104038731.jpg |
|
在阴影处理方面,光线追踪算法也同样有着得天独厚的优势。传统的光栅化渲染中,处理阴影大多使用阴影贴图的方式,这样的方式需要耗费大量的显存,并且难以实现抗锯齿效果。而在光线追踪算法中,光影计算是整个算法最基础的部分,无需对渲染引擎做任何修改就能实现真实的渲染效果。 http://www.mcplive.cn/images/201001/20100122104133217.jpg |
|
皮克斯和众多好莱坞大片,大多使用合成图片效果来构建虚拟世界。其中皮克斯使用了被称作REYES的基于光栅化原理的渲染算法。而光线追踪仅仅作为辅助渲染技术被引入到了其自家的Renderman渲染器中。一直到《Cars(汽车总动员)》这部动画,皮克斯才首次引入光线追踪算法。根据皮克斯的说法,即便是只用光线追踪算法来处理环境光吸收(ambient occlusion)等复杂计算,也让《汽车总动员》的运算量大幅增加,成本陡增不少。 http://www.mcplive.cn/images/201001/20100122104244738.jpg |
|
什么是BSP树 BSP树就是用来对N维空间中的元素进行排序和查找的二叉树,它被用来在空间中消除隐藏面。BSP树表示整个空间,BSP树中的任意一个结点表示一个子空间,这些结点将分成两个子空间,作为上面结点的子结点。 http://www.mcplive.cn/images/201001/20100122104316262.jpg |
|
|
|
光线追踪有着如此明显的优势,而且在实现方法上和现在的光栅化算法也没任何“不共戴天”之仇,那为什么我们至今仍然没有看到任何显卡能提供实时光线追踪渲染呢?答案首先是光线追踪惊人的运算量,即便光线追踪是并行度相当高的运算,在多内核时代计算机并行性能和内核数量几乎呈线性增长关系,但要实现每秒30帧的实时光线追踪计算,依然有很远的路要走。 根据Intel和Daniel的说法,要用光线追踪渲染出达到现代游戏的画面质量,同时跑出可流畅运行的帧数,每秒需要计算大概10亿束光线。这个数字包括每帧每像素需要大概30束不同的光线,分别用来计算着色、光照跟其它各种特效,按照这个公式,在1024×768这样的入门级分辨率下,一共有786432个像素,乘以每像素30束光线以及每秒60帧,我们就需要每秒能运算141.5亿束光线的硬件,而Intel双路4内核处理器每秒也不过只能处理830万束光线。 http://www.mcplive.cn/images/201001/20100122104410432.jpg |
|
在过去的几年间,显卡显存延迟的降低小得可怜。根据某显卡厂商的统计预期,在2004年显卡内存延迟大约在40ns左右,到了2014年显卡延迟也不过减少到了23ns—在10年间节省出来的17ns显然无法满足光线追踪技术的需要。而在这10年里,显卡的晶体管数量会从2.2亿只增加到22.37亿只。 既然传统的显卡架构和发展趋势,完全无法满足光线追踪算法的需求,那推倒重来会怎么样?2003年德国SaarLand大学就拿出了业界首个硬件加速光线追踪算法方案,这个被称作SaarCOR的光线追踪加速卡,使用FPGA(Field Programmable Gate Array现场可编程门阵列)堆砌,在66MHz的频率下就能获得和Pentium 4 2.5GHz相当的光线追踪性能。随后SaarCOR的研发人员接触到了IBM德国的技术人员,获得了一台拥有一枚CELL处理器的工程样机。在IBM技术人员的协助下,SaarCOR在短短两周的时间里就在这台机器上实现了全屏的实时光线追踪渲染效果。SaarCOR的研究人员目前已经在Cinema-4D上以插件方式实现了实时光线追踪。golem还透露了另外一个鲜为人知的消息,那就是SaarCOR其实获得了NVIDIA 2.5万美元的赞助,之前的F PGA原型就是在NVIDIA资助下进行的。SaarCOR至今未能量产,随后SaarCOR项目并入了OpenRT光线追踪开发项目中。 http://www.mcplive.cn/images/201001/20100122104450840.jpg |
|
在2009年3月,光线追踪的困局,由一家叫Caustic Graphic的公司打破。根据该公司的说法,他们的算法之所以独特是因为它解决了传统光线追踪算法偏向随机性的问题。新算法大幅提高了光线追踪计算地局部性,但这部分的算法需要一颗协处理器来完成。Caustic Graphics的工程师们相当明智,他们对于该硬件的定位仅仅是一颗专注于光线追踪运算的协处理器,而绝不会干越俎代庖的蠢事—Shader之类的传统光棚化操作依旧由GPU来完成。 我们之前已经提及,实现硬件光线追踪加速的命门在于存储子系统,Caustic展示的Caustic 1号样卡仅仅搭配了一条64bit DDR2 SO-DIMM内存,这和RV770的GDDR5显存规格对比有较大差异。由于知识产权保护,Caustic Graphics没有披露他们是如何解决存储瓶颈的,但在一个包含500万个三角形(包括两辆汽车的360万个)的场景中,所有可见效果都是使用一块Caustic 1光线追踪卡程序化光线追踪渲染而来的,实时帧率大约为3fps~5fps——这个数字虽然已经数十倍领先于显卡,但austic Graphics坦言,完全实现实时光线追踪化的游戏引擎还得等很多年,并估计至少四五年后他们的硬件才能在1920×1200分辨率下达到60fps的有效帧率。 在画面质量上拥有压倒性优势,在运算量上有着明显的劣势,这两大因素都让光线追踪算法看上去很美,用起来很累。由于当今显卡和CPU性能的制约,光线追踪始终无法达到实时可用的地步。与此同时,光栅化算法也没有在原地踏步,以《Forza赛车3》、《GT5》等游戏为首的光栅化算法阵营,已经逐步制作出了以假乱真的汽车反光效果和透明效果,如果不仔细看,很少有人能找到瑕疵。 http://www.mcplive.cn/images/201001/20100122104535805.jpg |
|
光线跟踪的基本原理
由光源发出的光到达物体表面后,产生反射和折射,简单光照明模型和光透射模型模拟了这两种现象。在简单光照明模型中,反射被分为理想漫反射和镜面反射光,在简单光透射模型把透射光分为理想漫透射光和规则透射光。由光源发出的光称为直接光,物体对直接光的反射或折射称为直接反射和直接折射,相对的,把物体表面间对光的反射和折射称为间接光,间接反射,间接折射。这些是光线在物体之间的传播方式,是光线跟踪算法的基础。 最基本的光线跟踪算法是跟踪镜面反射和折射。从光源发出的光遇到物体的表面,发生反射和折射,光就改变方向,沿着反射方向和折射方向继续前进,直到遇到新的物体。但是光源发出光线,经反射与折射,只有很少部分可以进入人的眼睛。因此实际光线跟踪算法的跟踪方向与光传播的方向是相反的,而是视线跟踪。由视点与象素(x,y)发出一根射线,与第一个物体相交后,在其反射与折射方向上进行跟踪,如图4.6.1所示。 http://202.118.167.67/eol/data/res/jsjtxx/Chapter4/46img/CG_Gif_4_028.gif 图4.6.1 基本光线跟踪光路示意 为了详细介绍光线跟踪算法,我们先给出四种射线的定义与光强的计算方法。在光线跟踪算法中,我们有如下的四种光线:视线是由视点与象素(x,y)发出的射线;阴影测试线是物体表面上点与光源的连线;以及反射光线与折射光线。 当光线V与物体表面交于点P时,点P分为三部分,把这三部分光强相加,就是该条光线V在P点处的总的光强: a) 由光源产生的直接的光线照射光强,是交点处的局部光强,可以由下式计算:
b) 反射方向上由其它物体引起的间接光照光强,由IsKs' 计算,Is通过对反射光线的递归跟踪得到; c) 折射方向上由其它物体引起的间接光照光强,由ItKt' 计算,It通过对折射光线的递归跟踪得到。 在有了上面介绍的这些基础之后,我们来讨论光线跟踪算法本身。我们将对一个由两个透明球和一个非透明物体组成的场景进行光线跟踪(图4.6.2)通过这个例子,可以把光线跟踪的基本过程解释清楚。 http://202.118.167.67/eol/data/res/jsjtxx/Chapter4/46img/CG_Gif_4_029.gif 图4.6.2 光线跟踪算法的基本过程 在我们的场景中,有一个点光源L,两个透明的球体O1与O2,一个不透明的物体O3。首先,从视点出发经过视屏一个象素点的视线E传播到达球体O1,与其交点为P1。从P1向光源L作一条阴影测试线S1,我们发现其间没有遮挡的物体,那么我们就用局部光照明模型计算光源对P1在其视线E的方向上的光强,作为该点的局部光强。同时我们还要跟踪该点处反射光线R1和折射光线T1,它们也对P1点的光强有贡献。在反射光线R1方向上,没有再与其他物体相交,那么就设该方向的光强为零,并结束这光线方向的跟踪。然后我们来对折射光线T1方向进行跟踪,来计算该光线的光强贡献。折射光线T1在物体O1内部传播,与O1相交于点P2,由于该点在物体内部,我们假设它的局部光强为零,同时,产生了反射光线R2和折射光线T2,在反射光线R2方向,我们可以继续递归跟踪下去计算它的光强,在这里就不再继续下去了。我们将继续对折射光线T2进行跟踪。T2与物体O3交于点P3,作P3与光源L的阴影测试线S3,没有物体遮挡,那么计算该处的局部光强,由于该物体是非透明的,那么我们可以继续跟踪反射光线R3方向的光强,结合局部光强,来得到P3处的光强。反射光线R3的跟踪与前面的过程类似,算法可以递归的进行下去。重复上面的过程,直到光线满足跟踪终止条件。这样我们就可以得到视屏上的一个象素点的光强,也就是它相应的颜色值。 上面的例子就是光线跟踪算法的基本过程,我们可以看出,光线跟踪算法实际上是光照明物理过程的近似逆过程,这一过程可以跟踪物体间的镜面反射光线和规则透射,模拟了理想表面的光的传播。 虽然在理想情况下,光线可以在物体之间进行无限的反射和折射,但是在实际的算法进行过程中,我们不可能进行无穷的光线跟踪,因而需要给出一些跟踪的终止条件。在算法应用的意义上,可以有以下的几种终止条件:
最后我们用伪码的形式给出光线跟踪算法的源代码。光线跟踪的方向与光传播的方向相反,从视点出发,对于视屏上的每一个象素点,从视点作一条到该象素点的射线,调用该算法函数就可以确定这个象素点的颜色。光线跟踪算法的函数名为RayTracing(),光线的起点为start,光线的方向为direction,光线的衰减权值为weight,初始值为1,算法最后返回光线方向上的颜色值color。对于每一个象素点,第一次调用RayTracing()时,可以设起点start为视点,而direction为视点到该象素点的射线方向。 RayTracing(start, direction, weight, color)
计算反射方向 R; RayTracing(最近的交点, R, weight*Wr, Ir); 计算折射方向 T; RayTracing(最近的交点, T, weight*Wt, It); color = Ilocal + KsIr+ KtIt; } |