转自:https://blog.csdn.net/hmbxsy/article/details/80509876?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://blog.csdn.net/wcm_lucky/article/details/88776524?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

光线追踪算法

前言

最近处于毕设答辩前的空档期,没什么要紧的事情要做,于是空闲之余随意看了下点计算机图形学,学习了一个画3D图形的光线追踪算法,在此简单地分享一下~

一、理论基础

1、三维场景中创建图像
  • 第一步:透视投影。这是一个将三维物体的形状投影到图像表面上的几何过程,这一步只需要连接从对象特征到眼睛之间的线,然后在画布上绘制这些投影线与图像平面相交的轮廓。
  • 第二步:添加颜色。图像轮廓绘制好之后,给它的骨架添加颜色,这样就完成了三维场景中的图像创建过程。

2、物体的颜色和亮度
  • 主要是光线与物体材质相互作用的结果。
  • 光由光子(电磁粒子)组成,光子由各种光源发射。当一组光子撞击一个物体时,可能发生三种情况:被吸收,反射或透射。发生这三种情况的光子百分比因材料而异,通常决定了物体在场景中的显现方式。然而,所有材料都有一个共性:入射光子总数总是与反射光子、吸收光子、透射光子的总和相同。
  • 白光由“红”、“蓝”、“绿”三种颜色光子组成。当白光照亮红色物体时,光子吸收过程会过滤掉“绿色”和“蓝色”光子。因为物体不吸收“红色”光子,所以它们将被反射,这就是物体呈现红色的原因。
  • 我们之所以能够看到物体,是因为物体反射的一些光子向我们传播并击中了我们的眼睛。我们的眼睛由光感受器组成,可以将光信号转换为神经信号,然后我们的大脑能够使用这些信号来辨别不同的阴影和色调。
3、光与物体的关系
  • 没有光线,我们都看不到周围的物体。
  • 周围环境中没有物体,我们看不到光。

二、光线追踪(RayTracing)算法描述

1、Forward Tracing

在用计算机生成的图像中模拟光与物体相互作用过程之前,我们需要了解一个物理现象。一束光线照射在物体上时,反射的光子中只有少数会到达我们眼睛的表面。想象一下,假设有一个每次只发射一个光子的光源,光子从光源发出并沿着直线路径行进,直至撞击到物体表面,忽略光子的吸收,该光子会以随机的方向反射。如果光子撞击到我们的眼睛表面,则我们会看到光子被反射的点。具体过程如下图所示。

现在从计算机图形的角度来看待这种情况。首先,我们用像素组成的平面代替我们的眼睛。在这种情况下,发射的光子将撞击图形平面上许多像素的一个,并将该点的亮度增加到大于零的值。重复多次直到所有的像素被调整,创建一个计算机生成的图像。这种技术称为前向光线追踪(Forward Tracing),因为我们是沿着光子从光源向观察者的前进的路径。

但是,这种技术在计算机中模拟光子与物体相互作用是不太现实的,因为在实际中反射的光子击中眼睛表面的可能性是非常非常低的,我们必须投射大量的光子才能找到一个能够引起眼睛注意的。此外,我们也不能保证物体的表面被光子完全覆盖,这是这项技术的主要缺点。

换句话说,我们可能不得不让程序一直运行,直到足够的光子喷射到物体的表面上获得精确的显示。这意味着我们要监视正在呈现的图像以决定何时停止应用程序。这在实际生产环境中是不可能的。另外,正如我们将看到的,射线追踪器中最昂贵的任务是找到射线几何交点。从光源产生大量光子不是问题,但是在场景内找到所有的交点将会是非常昂贵的。

2、Backward Tracing

这项技术为前向光线追踪技术的缺陷提供了一个方便的解决方案。由于我们的模拟不能像自然一样快速完美,所以我们必须妥协,并追踪从眼睛进入到场景中的光线。

光线照到一个物体时,我们可以通过将另一条光线(称为光线或阴影光线)从击中点投射到场景的光线,得到它所接受到的光子数量。这个“光线”有的时候会被另一个物体阻挡,这意味着我们原来的撞击点在阴影中,没有获得任何照明。

三、算法实现

1、基本原理
  • 光线追踪算法采用由像素组成的图像。对于图像中的每个像素,它将主光线投射到场景中。该主光线的方向是通过追踪从眼睛到像素中心线获得的。一旦我们确定了主射线的方向,我们就开始检查场景中的每个对象,看它是否与其中的任何一个相交。当发生主射线与多个对象相交的情况时,我们选择交点离眼睛最近的物体。
  • 然后,我们从交叉点向光线投射阴影射线。如果这条特定的光线在通往光源的路上不与某个物体相交,那么这个点就被照亮了。
  • 如果它与另一个物体相交,则该物体在其上投下阴影。
  • 最后,如果我们对每个像素重复这一操作,就可以获得三维场景的二维表示。
2、伪代码

光线追踪算法实现的伪代码如下所示:

  1. for (int j = 0; j < imageHeight; ++j) {
  2. for (int i = 0; i < imageWidth; ++i) {
  3. // compute primary ray direction
  4. Ray primRay;
  5. computePrimRay(i, j, &primRay);
  6. // shoot prim ray in the scene and search for intersection
  7. Normal nHit;
  8. float minDist = INFINITY;
  9. Object object = NULL;
  10. for (int k = 0; k < objects.size(); ++k) {
  11. if (Intersect(objects[k], primRay, &pHit, &nHit)) {
  12. float distance = Distance(eyePosition, pHit);
  13. if (distance < minDistance) {
  14. object = objects[k];
  15. minDistance = distance; // update min distance
  16. }
  17. }
  18. }
  19. if (object != NULL) {
  20. // compute illumination
  21. Ray shadowRay;
  22. shadowRay.direction = lightPosition - pHit;
  23. bool isShadow = false;
  24. for (int k = 0; k < objects.size(); ++k) {
  25. if (Intersect(objects[k], shadowRay)) {
  26. isInShadow = true;
  27. break;
  28. }
  29. }
  30. }
  31. if (!isInShadow)
  32. pixels[i][j] = object->color * light.brightness;
  33. else
  34. pixels[i][j] = 0;
  35. }
  36. }

四、加入反射和折射

1、基本原理

在光学中,反射和折射是总所周知的现象。反射和折射分向都是基于相交点处的法线和入射光线(主光线)的方向。为了计算折射方向,我们还需指定材料的折射率。

同样,我们也必须意识到像玻璃球这样的物体同时具有反射性和折射性的事实。我们需要为表面上的给定点计算两者的混合值。反射和折射具体值的混合取决于主光线(或观察方向)和物体的法线和折射率之间的夹角。有一个方程式精确地计算了每个应该如何混合,这个方程被称为菲涅耳方程。

加入反射折射后,进行以下三个步骤:

  • 计算反射

为此,我们需要两个项:交点处的法线和主光线的方向。一旦我们获得了反射方向,我们就朝这个方向发射新的光线。我们假设反射光线撞击了红色球体,通过向光线投射阴影射线来找出到达红色球体上的那个点的光线多少。这会得到一种颜色(如果是阴影,则为黑色),然后乘以光强并返回到玻璃球的表面。

  • 计算折射

注意,因为光线穿过玻璃球,所以它被认为是透射光线(光线从球体的一侧传播到另一侧)。为了计算透射方向,我们需要在知道击中点的法线,主射线方向和材料的折射率。

当光线进入并离开玻璃物体时,光线的方向会改变。每当介质发生变化时都会发生折射,而且两种介质具有不同的折射率。折射对光线有轻微弯曲的作用。这个过程就是让物体在透视时或在不同折射率的物体上出现偏移的原因。

现在让我们想象一下,当折射的光线离开玻璃球时,它会碰到一个绿色的球体。在那里,我们再次计算绿色球体和折射射线之间交点处的局部照明(通过拍摄阴影射线)。然后,将颜色(如果被遮挡,则为黑色)乘以光强并返回到玻璃球的表面。

  • 应用菲涅尔方程

我们需要玻璃球的折射率,主光线的角度,以及击中点的法线。使用点积,菲涅耳方程返回两个混合值。

这种算法的美妙之处在于它是递归的。迄今为止,在我们研究过的情况下,反射光线照射到一个红色的、不透明的球体上,而折射光线照射到一个绿色的、不透明的和漫射的球体上。但是,我们会想象红色和绿色的球体也是玻璃球。为了找到由反射和折射光线返回的颜色,我们必须按照与原始玻璃球一起使用的红色和绿色球体的相同过程。

这是光线追踪算法的一个严重缺陷。想象一下,我们的相机是在一个只有反射面的盒子里。从理论上讲,光线被困住了,并且会持续不断地从箱子的墙壁反弹(或者直到你停止模拟)。出于这个原因,我们必须设置一个任意的限制值,从而防止光线相互作用导致的无限递归。每当光线反射或折射时,其深度都会增加。当光线深度大于最大递归深度时,我们就停止递归过程。

2、伪代码

伪代码如下所示:

  1. // compute reflection color
  2. color reflectionCol = computeReflectionColor();
  3. // compute refraction color
  4. color refractionCol = computeRefractionColor();
  5. float Kr; // reflection mix value
  6. float Kt; // refraction mix value
  7. fresnel(refractiveIndex, normalHit, primaryRayDirection, &Kr, &Kt);
  8. // mix the two
  9. color glassBallColorAtHit = Kr * reflectionColor + (1-Kr) * refractionColor;

五、参考文献

英文:http://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-ray-tracing

源码:http://www.scratchapixel.com/code.php?id=3&origin=/lessons/3d-basic-rendering/introduction-to-ray-tracing

  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"><use xlink:href="#csdnc-thumbsup"></use></svg><span class="name">点赞</span><span class="count">22</span></a></li><li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-csdnc-Collection-G"></use></svg><span class="name">收藏</span></a></li><li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;1582594662_002&quot;}"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-csdnc-fenxiang"></use></svg>分享</a></li><!--打赏开始--><!--打赏结束--><li class="tool-item tool-more"><a><svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg></a><ul class="more-box"><li class="item"><a class="article-report">文章举报</a></li></ul></li></ul></div></div><div class="person-messagebox"><div class="left-message"><a href="https://blog.csdn.net/hmbxsy"><img src="https://profile.csdnimg.cn/C/7/B/3_hmbxsy" class="avatar_pic" username="hmbxsy"><img src="https://g.csdnimg.cn/static/user-reg-year/1x/4.png" class="user-years"></a></div><div class="middle-message"><div class="title"><span class="tit"><a href="https://blog.csdn.net/hmbxsy" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">菊厂小马哥</a></span></div><div class="text"><span>发布了1 篇原创文章</span> · <span>获赞 21</span> · <span>访问量 2万+</span></div></div><div class="right-message"><a href="https://im.csdn.net/im/main.html?userName=hmbxsy" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信</a><a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a></div></div></div>
    

蒙特卡洛光线追踪
对传统的逆向光线追踪的改进传统的逆向光线追踪算法有两个突出的缺点,就是表面属性的单一,和不考虑漫反射。我们不难通过模型的修正来缓解这两个问题。我们首先认为一个表面的属性可以是混合的,比如它有20%的成分是反射,30%的成分是折射,50%的成分是漫反射。这里的百分比可以这样理解,当一根光线打在该表面后,它有20%的概率发生反射,30%的概率发生折射,50%的概率发生漫反射。然后我们通过多次计算光线跟踪,每次按照概率决定光线的反射属性,这样在就把漫反射也考虑了进去。具体的算法如下:
从视点出发,经过投影屏幕上的每一个像素向场景发射一根虚拟的光线。
当光线与景物相交时按照俄罗斯轮盘赌规则决定他的反射属性。
根据不同的反射属性继续跟踪计算,直到正常结束或者异常结束。如果反射的属性为漫反射,则随机选择一个反射方向进行跟踪。
重复前面的过程,把每次渲染出来的贴图逐像素叠加混合,直到渲染出的结果达到满意程度。
蒙特卡罗光线追踪也需要使用空间划分技术来提高算法的效率,最常用的是平衡kdtree。

计算机图形学——光线追踪(RayTracing)算法相关推荐

  1. 计算机图形学之光线跟踪算法的研究与实现2017年我的优秀毕业论文

    计算机图形学之光线跟踪算法的研究与实现2017年我的优秀毕业论文 版权所有使用者请联系我 刘创 QQ:903188593 2.2.2 Phong光照模型 事实上对于漫反射的物体表面,使用Lambert ...

  2. 计算机图形学直线算法程序,计算机图形学直线生成算法实现.doc

    计算机图形学直线生成算法实现.doc (7页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 实验二直线生成算法实现班级08信计学号80姓名 ...

  3. 计算机图形学曲线算法代码,计算机图形学自由曲线绘制算法.doc

    计算机图形学自由曲线绘制算法 宁夏师范学院数学与计算机科学学院 <>实验报告 实验序号: 实验项目名称: 学 号姓 名专业.班实验地点指导教师时 间.实验内容与步骤 1 //TestVie ...

  4. 计算机怎样用计算法绘制圆弧,计算机图形学圆弧生成算法具体程序实现

    数学与软件科学学院实验报告 学期: 2010 至 2011 第一学期 2010年 10月 5日课程名称: 计算机图形学专业:信息与计算科学2007级5班实验编号: 03 实验项目: 圆弧生成算法 指导 ...

  5. 计算机图形学-光线追踪学习

    计算机图形学 光线跟踪算法 光线跟踪算法性质是比光线投射,缺点是需要假设光线在观察点处终止. 简介 为了生成在三维计算机图形环境中的可见图像,光线跟踪是一个比光线投射或者扫描线渲染更加逼真的实现方法. ...

  6. 【计算机图形学|直线生成算法】中点画线法

    文章目录 概述 一.基本思想 二.构造判别式: 三.递推出增量 优化: 总结: 四.例题分析 五.伪代码 概述 中点画线法(Midpoint Line Algorithm)是一种画线(Line Dra ...

  7. 光线追踪(RayTracing)算法理论与实践(三)光照

    提要 经过之前的学习,我们已经可以在利用光线追踪实现一些简单的场景.今天我们要探讨的是图形学里面的三种基本光源:方向光源,点光源,聚光灯. 不同于利用现成的Api,这次会从理论到实际一步步用C++实现 ...

  8. 计算机图形学--阴影1--PCSS算法

    阴影是怎么产生的,如何渲染出阴影 Shadow Mapping 假设要渲染以下场景 渲染场景2次: 1.第一次,产生一个shadow map,shadow map描述光源能照到的着色点. 2.从眼睛出 ...

  9. [计算机图形学]光线追踪的基本原理(前瞻预习/复习回顾)

    一.光栅化的弊端 我们为什么要用光线追踪呢,在之前的篇章中,我们提到了,光栅化的方式很难表示一些全局的效果,如(1)软阴影,(2)Glossy的反射(类似镜子但又不像镜子那么光滑的材质,如打磨的铜镜和 ...

最新文章

  1. eclipse CreateProcess error=87 的解决办法
  2. 美媒:谷歌巨型数据中心和美国小镇“抢水”
  3. Centos6.8 rsync 客户端安装与设置
  4. HikariCP连接池配置
  5. 求离散马尔科夫链的平稳分布+按照一定概率分布生成想要的样本
  6. 拼音缩写是啥意思_NMSL?AWSL?这些拼音缩写到底是啥意思?
  7. java 给图片添加暗水印_java 实现给图片添加水印
  8. 基于JAVA+SpringMVC+Mybatis+MYSQL的仓库管理系统
  9. oracle ORA-00001 违反唯一约束条件 SYS_C009225问题
  10. ubuntu 中下载openssh源码移植到 arm开发,出现you don't exist, go away问题的解决
  11. HTML函数多个条件并列,countifs多个并列条件(countifs同一列2个条件
  12. Java模拟账户---关键字this
  13. 现在有100块钱,一只公鸡5块,一只母鸡3块,三个小鸡1块。现在让你用100块钱买到100只鸡(大小不限)运用循环,和if语句实现
  14. c语言提取字符串里面的数字,一个截取字符串中数字的函数
  15. 面向中国企业关系抽取的双向门控递归单元神经网络
  16. 数据库之char vchar nchar nvchar的区别
  17. Grakn Forces 2020 D E F
  18. Java计算机毕业设计单位职工房产管理源码+系统+数据库+lw文档
  19. 文献推荐:大区域生态系统服务与社会生态驱动的空间关系——以黄河流域为例
  20. C语言/C++基础之小猪佩奇

热门文章

  1. 根据机器码实现软件注册
  2. 2016年开源巨献:百度71款开源项目
  3. html重要知识点总结
  4. H5/C3基础(2)
  5. 深度参与 openGauss Developer Day 2022,云和恩墨在多项活动中展风采
  6. 5G步入规模化商用关键期
  7. C++如何获取虚函数表(vtbl)的内容及虚成员函数指针存放原理
  8. RuntimeError: Expected object of type torch.cuda.LongTensor but found type torch.cuda.IntTensor
  9. 灌区续建配套与信息化改造工程--设备选型
  10. Linux从头学09:x86 处理器如何进行-层层的内存保护?