光线追踪

前言
  • 写一点困惑
  • 我看了关于光线追踪的教程视频,对其原理有了认识
  • 看到最后,老师布置作业不让用OpenGL,因此只能用C++手动敲代码
  • 我完全不知道该怎么入手,一脸懵逼
原理
  • 从视点发出一条射线,然后透过屏幕的某个像素点,然后与场景中物体相交,取相交的第一点,然后利用Phong模型,计算其颜色值,再从该点引发反射和折射光线(根据物体的材质不同,金属没有折射,直接被吸收了。透明材质的折射光线会与后面的物体相交,并且反映后面物体的颜色值),计算这两个光线与其它物体的交点,并计算交点的颜色值,与初始颜色值叠加,一直迭代下去,直到光线衰减为0。
  • 利用这个算法,可以实现阴影,反射,折射等效果
步骤
光线投射
  • 明暗效果仅仅由第一次相交的物体表面法线方向,材质,视点和光照方向,以及光照强度等因素共同考虑
  • 光线投射并不考虑第二层以及更深层次的光线,因此不具有阴影,反射,折射等效果
添加阴影
  • 计算阴影区域时,只关心是否与物体相交,而不关注哪个是最近交点
折射效果与反射效果
  • 计算光线在交点处被物体反射和折射所产生的新的光线的方向,新的方向由入射光方向,物体表面法向,以及介质共同决定
  • 对新产生的光线分别继续进行跟踪
  • 反射方向 R=I-2(I.N)N
  • 折射方向的公式很复杂。
递归结束
  • 有些物体并不透明
  • 递归深度
  • 在光线弹射一定次数后停止
  • 光线的贡献
  • 在光线的贡献衰减到足够小时停止
关键
  • 因此光线追踪算法的关键就是如何计算射线和各个图形的交点
平面类
  • 平面类进行计算,光线本身有一个方程,平面本身也有一个方程,直接联立方程组,计算出交叉点即可。
  • 计算出交叉点只是表明该位于平面上,但不一定在该平面范围内。
  • 所以我们需要判断该点是否位于该平面范围内。因此也引发了很多有趣的算法。并且这涉及到计算几何
光线的表示
  • 这里将光线作为从眼睛射出的射线
  • P(t) = R0+t*Rd
  • R0是光线的源点,Rd代表光线的朝向,Rd是单位向量
  • 参数t代表光线到达的位置
  • 在光线的正方向上,参数t都是正数,t>0
平面的表示
  • 由法线和该平面上的任意一点可以确定一个平面
  • 显示表示P0 = (X0,y0, z0),n=(A,B,C)
  • 隐式表示H(P)=Ax+By+Cz+D=0(n.P+D=0)n与P是点乘
  • 当n是单位法向量时,距离就是H(P)(见距离公式)
获得解
  • 直接联立两个方程获得解
  • t=-(D+n.R0)/(n.Rd)
  • 需要验算t>0
三角形平面
  • 在实时图形学中,基于三角形的几何表示十分常见,可以使用三个顶点坐标来表示
  • 重心坐标(也是需要数学证明)
  • 三角形P0P1P2内的一点P可以表示成P=aP0+bP1+cP2
  • (a,b,c)被称为重心坐标,满足大于等于0小于等于1,a+b+c=1
  • 有许多其它的应用,纹理映射,法向插值,颜色插值等
  • 性质,将点P连接P0,P1,P2,然后计算分割出来的三个三角形的面积占总面积的比例,就是abc的值。相反,我们只要给出abc,相加等于1,那么就一定能找到一个点在该三角形内。
  • 然后联立光线方程与重心坐标方程获得一个方程组
  • 计算就可以知道
  • 需要验算t>0并且b+c<=1
多边形平面
  • 虽然三角形比较常用,但是多边形也需要用到,因此需要一个普遍性的求交算法
  • 判断是否在多边形内部,将交点以及多边形的所有顶点投影到XY,YZ,ZX平面中一个,在二维平面上进行处理
  • 问题转变为判断一个点是否在多边形的内部(计算几何学科的问题)使用交点检测算法
交点检测算法
  • 是所有不进行预处理的方法中最快的
  • 基于Jordan曲线定理(如果一点在多边形内部,当且仅当由该点发出的任何一条射线与多边形的边界有奇数个交点。如果是外界就会有偶数个算法)
  • 几种特殊情况
  • 我们会遍历将该射线分别和三角形的几条边求交点
  • 如果该射线穿过多边形的顶点,那么是按照一个交点还是两个
  • 但是如果该射线与某条边平行,并且穿过该边,那么就有无数个交点
  • 技巧
  • 以检测点为原点,发出的射线为正坐标轴,作为检测交点的射线
  • 如果某条边的y坐标符号相同,则与x轴无交点
  • 否则,计算这条边与x轴的交点
    • 位于x轴正半轴上,交点个数的变量+1
    • 否则,与x轴正半轴没有交点(这样做还是没有解决上面两个特殊情况)
弧长法
  • 按照顺时针给多边形的顶点标记ABCDE
  • 然后依次连接PA,PB,PC,PD,PE
  • 再去计算这几个边之间的夹角之和,最后等于2π,在内部。等于0在外部。
  • 因为要求角度所以很麻烦,但是很稳定。一点误差也没有关系(上一个算法不稳定,因为有特殊情况。如果错了就完蛋)
  • 升级版本
  • 我们不直接计算角度,而是以该点为坐标原点,然后计算各象限内点的符号
  • 事先规定,如果顶点Pr的某个坐标为0,则其符号为正。都为0就是被测点,预先排除。
  • 然后根据象限变化
  • 1-1 同一个象限 0
  • 1-2 π/2
  • 1-3 ±π(可能为正或者负号
  • 1-4 -π/2
  • 当边的终点在与起点相对象限时,弧长变化增加或者减少π
  • 这里通过二维形式的叉乘来计算,(x1,y1)和(x2,y2)分别是起点与终点
  • f=x1y2-x2y1
  • f=0,则穿过坐标原点,f>0,弧长代数和增加π,f<0,弧长代数和减少π
球体
  • 和平面类似,直接联立方程组,然后求出相交点。但是这样很麻烦并且有一些缺点
    • 我们不需要相交的第二个点
    • 可以加速
  • 用几何方法
    • 首先连接光源点和球心并计算两者之间的距离
    • 然后和r的平方作对比,如果大于该r的平方,则说明光源点在球体外否则在球体内。当相等的时候,则位于球上。(要考虑退化。什么是退化?)
    • 然后计算球心与光源点向量到光线方向的投影tp(即光源点到球心沿光源方向的距离)
    • 如果光源在球外,并且投影距离小于0,则光线不与球面相交
    • 然后计算球心到光线所在直线的距离d,如果d大于R,则 光线与球面也不相交
    • 然后计算球心到光线方向的投影点与交点的距离t,如果光源点在球内,那么交点s=tp+t,如果光源点在球外,s=tp-t
长方体
  • 我们可以用长方体将三维模型包裹,然后计算光线是否与该长方体相交,如果相交就再计算与该三维模型的交点。不相交就直接忽略
  • 因此长方体经常用来进行光线追踪加速
  • Slab算法与Woo算法
    • Slab算法
    • Slab是两个互相平行的一组平面
    • 计算该光线与长方体的三组Slab的交点,p1max,p1min,p2max,p2min ,p3max,p3min
    • 然后取max里面的最小点Pmax与min里面的最大点Pmin。Pmin要小于Pmax,然后这就是与长方体相交的两个点了。如果Pmin不小于Pmax,那么该光线不与长方体相交
    • 至于为什么,教程里面用一个二维图像验证了。但是具体的证明估计要用到数学。不想深究
    • Woo算法
    • 该算法是建立在这样一个基础上,沿坐标轴进行放置
    • 我们取比较近的三个平面,(去掉背相面)
    • 然后获得光线与该三个平面的交点,
    • 将这三个t值中的最大一个对应的点作为可能的交点
    • 检查这个可能的交点是否位于长方体的表面上,如果不在,则光线与长方体不相交
    • 两者的计算复杂度类似
    添加纹理
  • 纹理自身分为二维纹理与三维纹理
  • 进行光照模型计算的时候,我们需要使用与该模型上的某点的颜色
  • 但是如果贴上纹理,就要取该点所对应的纹理的颜色值
  • 因此我们需要进行纹理映射
  • 以矩形表面为例
  • 为矩形的四个顶点指定二维纹理坐标
  • 计算矩形内部与光线的交点的二维纹理坐标(双线性插值)
  • 使用该纹理坐标在纹理图上进行查找,根据查找结果赋予交点相应的颜色值
一些思考
  • Epsilon问题,计算精度问题
  • 当光线与平面,球面相切,或者与多边形相交于某个顶点时,需要仔细考虑
  • 加速算法
  • 使用包围盒加速Bounding
  • 使用层次结构加速 Hierarchical Structure 加速
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
For those that do not know me: My name is Jacco Bikker, also known as 'Phantom'. I work as '3D tech guy' at Overloaded, a company that develops and distributes games for mobile phones. I specialize at 3D Symbian games, which require highly optimized fixed-point, non-HW-accelerated 3D engines, crammed into 250Kb installers. So basically I'm having fun. As software rendering used to be my spare time activity, I was looking for something else. I tried some AI, which was great fun, and recently I dove into a huge pile of research papers on raytracing and related topics; such as global illumination, image based lighting, photon maps and so on. One document especially grabbed my attention. It's titled: "State-of-the-Art in Interactive Ray Tracing", and was written by Wald & Slusallek. I highly recommend this paper. Basically, it summarizes recent efforts to improve the speed of raytracing, and adds a couple of tricks too. But it starts with a list of benefits of raytracing over rasterization-based algorithms. And one of those benefits is that when you go to extremes, raytracing is actually faster than rasterizing. And they prove it: Imagine a huge scene, consisting of, say, 50 million triangles. Toss it at a recent GeForce with enough memory to store all those triangles, and write down the frame rate. It will be in the vicinity of 2-5. If it isn't, double the triangle count. Now, raytrace the same scene. These guys report 8 frames per second on a dual PIII/800. Make that a quad PIII/800 and the speed doubles. Raytracing scales linearly with processing power, but only logarithmically with scene complexity. Now that I got your attention, I would like to move on to the intended contents of this crash course in raytracing.
内容介绍在成像领域,我们有很多手段。比如你可以通过照相机的光学元件,也可以通过像电脑游戏中的那样,通过GPU的一套渲染管线来实现成像。当然除此之外是不是就没有其他的成像方式了呢?当然答案是否定的。 在我们不去使用计算机图形学那套去成像的时候,最土鳖和最容易理解的成像方式就是光线追踪了。这里同学们应该理解到的有一个点,第一光线追踪不是唯一的成像方式,第二它与传统的GPU成像或者说 计算机图形学里说的那些光栅化之类的从思路上就有区别,第三光线追踪是最简单的成像方式之一,大概你学完高中数学就可以实现光线追踪,写完两三个C++类足以做成非常优质的画面。所以同学们要对光线追踪有一个 清晰的认识,不要认为你学完这一套就无敌了,其实你学完了才会发现,这比OpenGL那些一套一套的规则简单多了。 大部分情况下,由于光线追踪不是按照图形学那边的那些管线来做的,所以它不讲究效率,而是遵循物理意义上的画质最佳。所以基本上你学会光线追踪,且不从事电影行业或者不学习引擎内核去研发高端引擎,那么这块知识估计你会带进坟墓。适合人群光线追踪适合于那些探究画质的同学,你可以轻松的把你的思维应用到你的算法中,但大概率无法转化成为实时算法,也就是无法转化成传统渲染管线这边的一套一套的东西。因为仿真从算法出发点上就是不考虑效率的。 你可以用光线追踪去渲染一些精致的画面,如果你是学习了游戏引擎了的话,你可以尝试自己写一个光线追踪的渲染器,来执行烘焙场景的操作。大部分情况下,通用引擎会使用AutoDesk的Beast SDK,比如Unity3D 里面就有beast.exe。如果你是游戏引擎的内核程序员,那么你有可能将你光线追踪和离线渲染学来的知识通过烘焙场景的方式来应用到你的实际工作中。光线追踪的地位在实时渲染领域中使用光线追踪的算法的探索当然也有人在做,这其中最厉害的当然就是Unreal,值得我们学习。如果你在你的引擎内核里使用了像vulkan这样的高级别渲染器,兼容性会差一点,但是你此时 就可以学习Unreal做光线追踪的思路,在实时渲染中,去或多或少加一点光线追踪。我们可以来思考这样的一个问题,实时渲染追求的是速度与性能,离线渲染追求的是极限画质。于是乎那些大神,或许未来你 就是这些大神中的某一个,你们做的操作莫过于把离线渲染算法中的某一部分比较烧性能的环节,比如通过IBL的方式事先通过离线渲染把所有渲染数据存储到一张图像里去,然后在实时渲染的时候把这张图片 中的数据取出来直接运算,就可以得到比实时渲染好,但是比离线渲染差那么一点点画质。这里之所以无法让实时渲染和离线渲染的画质完全一致是因为我们的3D世界就如同我们的眼球一样精度是很高的。如果你的 图片的分辨率不够大,离线渲染的时候存储的数据都是比较粗糙的采样数据,无法描绘出一个精致的世界。课程安排在我们的课程中,我们来通过最简单的方式,依然是最简单的方式来理解光线追踪是怎么玩出来的。画面或许很好看,但都是简单的高中几何数学,即便我们认为你没写过程序都能看懂意思。我们课程里面不涉及 物理渲染,我们使用的依然是经典的lambert这样的光照模型。物理渲染的方式既可以在实时渲染里实现,也可以在离线渲染里实现。大体的框架不会变,只是计算光的时候算法会变,那部分估计也不是美术可以听懂的了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值