课程一共分为四个大的板块,目前已经学习了光栅化和几何,可以实现图1和2的效果,下面要来学习第三个大的板块,光线追踪。
在学习光栅化时,我们在进行着色的过程中实现光照效果的时候可以发现,我们实现了环境光、漫反射、镜面反射,但是确没有做出阴影。因为光栅化考虑的只是一个局部的着色的过程,只是对那一个像素周围的区域进行着色,并没有考虑到全局进行着色,所以在实现物体表面的光照效果的时候,无法实现对应的阴影。
而光线追踪可以做到:
实现软阴影
能够很好的解决全局光照的问题
上面三个图都是需要通过光线追踪来进行实现,特别是最后一个间接光照。我们在用光栅化进行着色的时候,对于环境光直接按照一个常数进行处理,但是实际上环境光的出现并不是经过一次反射得到的,比如上图图3,光线经过窗子射入屋内,然后光线撞到地板上进行反射,反射到天花板上在进行一次反射,最后反射到桌上。要实现更好的光照效果,就不能像之前那样单纯的将环境光设置为一个常量,所以需要光线追踪来实现。
上图是绝地求生中的游戏截图,可以看到图片上的纹理非常粗糙,并且没有阴影,光照的效果也非常差。光栅化进行着色速度很快,但是质量确比较低,因为之前在学习光栅化的时候也可以发现,光栅化在很多地方都是进行一种近似的处理,比如插值,采样等过程,所以得到的效果并不好。
而上图就是光线追踪的应用效果了,可以看到实现的效果非常的好。光线追踪得到的效果更加精确,但是,其速度确非常的慢。
光栅化更加适合实时(real-time)的渲染,比如在游戏领域,游戏需要较快的速度
光线追踪更适合离线(offline)的渲染,比如在制作上图的这种动画电影,都是将程序写好之前花大量的时间运行出来,然后组成电影,比如上面这一张图的渲染,就需要消耗10k个CPU时间。虽然目前也开始在游戏中应用光线追踪技术,如战地5,古墓丽影暗影等、但是开启光线追踪的效果之后帧数下降明显,只有高级游戏显卡才能够较为流畅的游玩。
介绍了这么多,下面开始介绍具体的光线追踪算法
在介绍算法之前,关于光线有一些说明:
平面是物体的投影平面,后面是实际的物体。光线的投射的过程:假设我们目前在往一个虚拟的世界看,我们是透过投影上面的投影的屏幕向虚拟世界中看,投影的平面被我们分成了由许多个像素组成。
上面这一个过程就是利用光路的可逆性,正常是从光源到物体到人眼,而颠倒这个过程,就能够对光线进行追踪。
下面看一个具体的光线投射的例子
在这之前,有一些事情需要先声明一下:
通过这种方法能够获得和光栅化近似相同的结果。在这里光线只弹射了一次,后面就介绍光线弹射多次的方法。
Whitted光线追踪的着色效果就如上图。两个球分别实现了折射和反射,阴影的程度也不相同,在这个方法中就计算了光线的多次弹射,能够实现一个很不错的效果。
算法的具体说明如下:
还是之前的场景:
在了解了上面Whitted风格的光线追踪之后,要实现这个算法我们还需要知道如何求光线和面的交点。
从上个图可以看出,要定义一条光线,只需要知道光线的出发点(点光源)和光线射出的方向向量即可,所以光线的代数定义如下:
上面的表示的是,在时间t时,光线的所到达的位置。t = 0时,光线还未出发,此时的光线是一个点,t = 1时,光线从原点出发,经过单位时间到达了o + d的位置,o和o + d两个点的连线,就是此时的光线。
第一个公式为光线的公式,第二个公式则是球面的隐式表示公式。在数学中求一条线和一个面的交点时,只要令两式想等,求得的解就是线和面的交点。所以光线和球面的交点的求法也是将两个等式相等求解,经过化简,就可以得到下面的式子:
求出t,就可以得到交点,其中o , c , R 已知。然后再将该式子展开,使用求根公式,即可得到解。
二次方程的根有三种情况,分别是0、1、2个根,不同的根的数量对应的交点情况如下:
前面在介绍隐式曲面时已经说过,隐式曲面是使用一个等式来表示
求光线和隐式表示的曲面的交点的方法和上面类似,直接代入求解即可。
比如下面这些曲面求交点,直接带入即可。
隐式表达的曲面通过上面的方法就可以求解,那么显示表达曲面该怎么办?就是通过求光线和三角形的交点。
通过求光线和三角形的交点,能够判断这个交点处是否在阴影内,是否可见、等等。并且还能够判断给定的一个点是在物体内还是在物体外面。比如有一个物体,有一个点,从这个点发出一条光线,光线是一条射线,如果点在物体内,那么光线和物体的交点一定是奇数个,如果在外,则是偶数个。
说那么多,那么该如何计算光线和三角形的交点?
我们都知道三角形是处在一个平面上的,于是要求光线和三角形是否有交点,则可以按照如下的方法:
要确定一个平面,需要该平面的法向量和平面上的任意一点。
平面的等式如下:
p代表该平面上的任意一点,p‘代表平面上已知的一点,N代表法向量。平面方程的一般表示形式为:
有了光线和平面的等式,直接将光线等式带入求解即可。
前面让每个三角形都和每一个光线进行交点的计算,那么复杂度 = 像素的个数 * 三角形网格的个数(在前面介绍光线追踪时,我们提到过,人眼从发出的光线会穿过每一个像素)。这种方法虽然有效,但是速度太慢,所以要对其进行改进,减少计算量,加快运行速度。
我们使用的方法是包围体(Bounding Volumes)。
前面在光栅化的部分,我们学过一个包围盒,这里的包围体的思想与前面类似。
包围体的思想是:
我们一般使用轴对齐包围盒,轴对齐包围盒就是由三对相互垂直的平面所围成的一个立体空间。,如下图所示,只展示出了其中一对盒子。
以2D的情况为例,3D的情况类似。在上面提到过,AABB是由三对相互垂直的平面所围成的,那么在2D的情况下,AABB就是由两对相互垂直的面所围成。
上图表示求光线和包围盒交点的过程:
核心思想:
当光线和每一对平面都有交点时,光线才会进入包围盒。
当光线离开任一对平面时,光线也就离开了包围盒。
对于每一对平面,我们都要计算出t(min)和t(max),分别代表了光线的进入和离开的时间,t可以是负数。
对于每一个3D的包围盒,我们要对上一步算出的时间区间进行求交集。
如果t(enter) < t(exit)时,我们就知道,光线曾有一段时间是在盒子内部,也就是说光线和包围盒有交点。
有一些特殊情况:
总而言之,如果光线和包围盒有交点,则应该满足:
使用轴对齐包围盒求交点非常简单。只要当光线的某一分量等于某一个特定值的时候,就说明光线和这个轴对齐的平面有交点了。
发现把所有的论文提纲写在一篇博客里我自己翻起来也很难受,干脆还是一篇论文一篇博客了。跟之前很多使用神经机器翻译(NML)不一样的是,本文使用了一种PIE架构,Parallel Iterative Edit Models,与普通的seq2seq问题相比,这种建模是seq2edits,与其他方法确实有创新之处,并且目前在CONLL2014排行榜上雄踞第四,虽然前三都是NML方法做的,但是这种PIE...
对于移动平台上的RPG类的游戏,我们常用虚拟摇杆来控制人物角色的行走和一些行为,相信我们对它并不陌生,之前尝试了EasyTouch2.5,发现并没有最新版的3.1好用,2.5版本的对于自适应没有做的很好,而最新版的已经解决了这一问题。当然unity也自带了摇杆Joystick,用起来也简单,但存在不少局限,不会满足普通mmo游戏的需求,比如指定显示区域或者是更改一些素材等等,而这些EasyTouc..._easytpuch 去掉虚拟遥感
上一篇文章中我们介绍了泛型的基础知识点,详情请参考文章:详解Java泛型之1——入门泛型必懂的知识点今天我们来继续讲解泛型中另一个非常重要的概念,就是那个“小问号”——通配符!通配符概念泛型中除了用 表示泛型外,还有 这种形式。?被称为通配符。那么引入通配符的原因又是什么呢?看下面这段代码:public classCar{ public void drive() { System.out.println("car的drive方法"); };..._<? super t>被称作有下限的通配符
分析 AIX 和 Linux 性能的免费工具,这个高效的工具可以工作于任何哑屏幕、telnet 会话、甚至拨号线路。另外,它并不会消耗大量的 CPU 周期,通常低于百分之二。在更新的计算机上,其CPU使用率将低于百分之一。使用哑屏幕,在屏幕上对数据进行显示,并且每隔两秒钟对其进行更新。然而,您可以很容易地将这个时间间隔更改为更长或更短的时间段。如果您拉伸窗口,并在X Windows、VNC..._nmon
//C程序设计第四版(谭浩强)//章节:第八章 善于利用指针 //题号:8.5//题目:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),//凡报到3的人退出圈子,问最后留下的是原来第几号的那位。 #include <stdio.h>void pick(int *p,int n){ int i,cnt,sum; for(i=0;i<n;i++) ...
Python:2.7版本Blender: 2.9版本通过外部Python调用cmd命令行,不启动Blender界面,执行BlenderPython代码,并传递参数,然后进行模型操作、渲染等等。cmd调用的命令:blender.exe -b -P python_blender.py – arg1 arg2其中arg1和arg2是cmd传递的参数读取参数用arg1 = sys.argv[-2]arg2 = sys.argv[-1]外部Python:python_cmd.pyimport os_blender.exe -b
Horovod源码剖析:核心模块 – operationshorovod/common/operations.h首先了解一下mpi常见的通信操作MPI-Scatter:scatter与broadcast类似都是一对多的通信,将一段array 的不同部分发送给所有的进程MPI-Boardcast:与scatter进行区分,broadcast是将0号进程将相同的信息发送给所有的进程;MPI-Gather:MPI_Gather和scatter刚好相反,他的作用是从所有的进程中将每个进程_horovod mpi_allreduce
BLDMAKE ERROR: Directory "/Symbian/9.2/S60_3rd_FP1/EPOC32/" does not exist WaitNote出现这样的问题,解决办法是吧工程考到Symbian所在的安装盘下,如Symbian安装在C:就把工程考到C:,然后重新引入工程,再编_prgmip32.coe does not exist
谷歌研究科学家Jon Barron提出了关于无界场景重建的新的观点——Mip-NeRF 360,该论文从三个方面提出了新的观点,使用非线性场景参数化、在线“蒸馏”和新颖的基于失真的优化器来克服无界场景带来的挑战。与 mip-NeRF 相比,均方误差降低了 57%,并且能够生成逼真的合成视图和详细的深度用于高度复杂、无界的现实世界场景的地图。..._nerf新进展
一、np.var数学上学过方差:$$ D(X)=\sum_{i\in [0,n)} ({x-\bar{x}})^2 $$np.var()实际上是均方差,均方差的意义就是将方差进行了平均化,从而使得此值不会随着数据的增多而发生变化。np.std()是标准差,np.std()的平方等于np.var(),标准差在高斯分布中用$\sigma$表示。不论是方差还是标准差,它们衡量的都是二阶..._numpy 方差
题目描述:给定长度为N的数组A[0...N-1],求递增且连续数字最长的子数组。eg:1,2,3,34,56,57,58,59,60,61,99,122的连续数字最长的一段为56,57,58,59,60,61算法分析:遍历数组,从下表为1的开始,如果A[i]-A[i-1]==1,A[0....i-1]的连续子数组长度len加一,否则置最长连续子数组长度为1,并每次更新最长连续的长度maxLen(比...
Rollup 学习笔记一、Rollup的认识二、Rollup插件的使用1. rollup-plugin-json2. rollup-plugin-node-resolve3. rollup-plugin-commonjs一、Rollup的认识rollup官方文档相比于webpack来说更为小巧Rollup 仅仅使一款ESM打包器(默认只能够处理 ESM 的模块),而webpack配合plugins可以实现大部分前端工程化的需求。打包的结果更加的扁平。打包会以 tree-shaking 的形式进_parcel 访问json文件