第三节 室内场景中光照运算

关于Radiosity的算法最早是由Goral、Cindy M、Torrance、Kenneth E、Greenberg、Donald P、Battaile和Bennett在论文《Modelling the interaction of light between diffuse surfaces》提出的。他们使用Radiosity来模拟能量在漫反射表面之间进行传送,漫反射表面对照到表面上的光线在所有的方向上都进行相同的反射,和它相反的是镜面反射表面,它只在反射方向上传播反射光。由于漫反射表面的这个特性,这就意味着对于所有的观察角度而言看起来表面都是相同的,这样对于场景中的每一个表面只需要进行一次光照运算,而且可以在场景的预渲染时进行,因此这项技术被大量的3D游戏所采用。
下面我再简短的讲解一下Radiosity是如何工作的,而将主要的精力放在如何使用BSP树来加速Radiosity的计算,对于Radiosity的详细介绍请参考前面的章节。Radiosity技术是设计用来使场景中光照看起来更加真实和光滑,如果我们使用一个一直向前传播而不考虑反射的光照模型,那么当场景中的灯光照亮场景中的物体时,并不会计算远处经过反射过来的光线,这样场景中的阴影看起来非常尖锐而物体表面也看起来非常不真实。为了使用radiosity技术我们需要把场景分割成一块一块很小的部分,每一部分我们称它为patch,每一个patch都有一个初始化的能量级别,如果它不是一个灯光这样的发光体的话通常为0,有许多方法来分配场景中的能量,这里我们将要使用的方法称为交互式radiosity。这个方法的过程是我们从场景中未发送能量的级别最高的patch开始发送能量,能量经过传递后将不再发送能量的patch的等级设为0,重复这个过程直到场景中的每一个patch的能量等级都小于一个预定值为止。
当能量从一个patch(j)开始发送到另一个patch(i)时我们使用下面的公式:
Bi = Bi + Bj * Fij * Ai / Aj
这里Bi = patch(i)的能量级别     Bj = patch(j)的能量级别 
    Ai= patch(i)的作用区域    Aj = patch(j)的作用区域
    Fij = patch(i)与patch(j)之间的系数
在公式中系数Fij是由以下公式来确定的:
Fij = (cos qi * cos qj) / d2 * Hij
这里Fij = patch(i)与patch(j)之间的系数
qi = patch(i)与patch(j)法线之间的夹角
qj = patch(i)与patch(j)法线之间的夹角
d = patch(i)与patch(j)之间的距离
Hij = patch(i)与patch(j)之间的可见性系数。如果在两个patch之间只有一条光线可以跟踪,这个值为1,如果没有光线可以跟踪为0。一般情况下由于每一个patch都不是一个点而是一个区域,因此光线有很多条。
从上面的公式中我们可以看到在场景中进行radiosity计算是非常耗费时间的。这个函数的复杂度为O(n3),这里的n为场景中patch的数量。由于对于场景中每一个patch你需要发送最少一条光线到其它patch上,因此需要对场景中的几乎所有的多边形都进行光线跟踪计算。在上面的公式中系数H的计算非常耗费时间,下面我们将看一下如何在BSP树中对它的计算进行优化。

BSP树中的radiosity计算
在进行场景中的光照计算之前需要把场景中的面分割为patch,一个方法是在开始的时候设定每一个patch为预定的大小,当计算每一个patch的能量时,如果在patch上的能量足够大,对这个patch进行分割。不过这个方法是非常耗费时间的,因此必须寻找一个更好的方法来通过BSP树对计算进行优化。
在radiosity的一般算法中场景中的每一个光源都被看作为一个或多个patch,这里我们可以改进一下,将每一个光源放在它所位于的叶节点中,接下来每一个光源都发送自己的能量到场景中所有的patch上,当这个过程完成后radiosity计算也就结束了。为了使最后的结果看起来更好可以使用一种称为“渐进精选”(progressive refinement)的技术来对这个方法进行很小的修改。在每一次过程中,叶节点中具有高能量的patch将发送能量到其它低能量的patch上,这样做的结果是高亮度的patch将发送能量到处于阴影中patch上。这是因为在实际生活中并没有真正黑暗的地方,它多多少少要获得一些其它物体反射过来的光亮。
由于计算非常耗费时间需要做一下优化,使用渲染BSP树时获得的PVS信息可以在选择哪些patch将接受能量时剔除一些无用的计算。因为在计算PVS时使用了相同的方法来进行光线跟踪。
通过场景来分配能量的算法如下:
l 函数RADIOSITY
l 参数:
l Tree – 进行radiosity计算的BSP树。
l 返回值:
l None
l 功能:
l 在场景中的patch之间发送能量。
RADIOSITY (Tree)
1 for(each leaf L in Tree)
2 for(each light S in L)
3 for(each leaf V that is in L’s PVS)
4 Send S’s energy to the patches in V
l 下面语句5是为了让地图编辑者在任何时候都可以检查场景渲染的效果,如果他感到看起来已经足够好了可以中断能量的传播。
5 while(not looks good enough)
6 for(each leaf L in Tree)
7 for(each leaf V that is in L’s PVS)
8 Send energy from the patch with the most unsent energy in L
to all patches in V.

复杂度分析
这个函数的运算费用实在是太高昂了,可以称为时间杀手,在最坏的情况下每一条光线将不得不检测场景中的每一个多边形,此时复杂度为O(n3),这里n为树中patch的数量。一般情况下由于进行了优化可以减少大量的计算,但是减少多少并不能计算出来,因为这依赖于树结构的复杂度。
上面的函数给出了一个充分利用BSP树的优点来加速场景光照运算的方法,尤其是可以显著的减少光线跟踪的计算量,而且地图设计者可以来决定当场景渲染时如果渲染的效果可以接受中断渲染循环。这对地图的预渲染实在是太方便了,运行的时间可以根据渲染的效果来决定。

第四节 BSP树的预渲染
现在我们需要完成一个完整BSP引擎的预处理过程,下面的算法显示如何将场景渲染到BSP树中。
l 函数RENDER-SCENE
l 参数:
l Scene – 被渲染的场景
l 返回值:
l 一个BSP树。
l 功能
l 预渲染来获得一个包含场景信息的BSP树。

RENDER-SCENE (Scene)
l 使用描述场景中图元的物体来渲染BSP树。
1 GeometryPolygons = {}
2 for (每一个包含场景图元的物体object O)
3 GeometryPolygons = GeometryPolygons U O.PolygonSet
4 GENERATE-BSP-TREE (Tree.RootNode, GeometryPolygons)
l 分配叶节点上的取样点。
5 DISTRIBUTE-SAMPLE-POINTS (Tree.RootNode, {})
6 TRACE-VISIBILITY (Tree)
7 for 每一个场景中的静态物体object O
8 for 物体O中每一个多边形P
9 PUSH-POLYGON (Node, P)
l 函数CREATE-PATCHES是一个未定义的函数,由于我们的解决方案效率并不是太好,因此没有对它进行详细的介绍。
10 CREATE-PATCHES (Tree)
11 RADIOSITY (Tree)

复杂度分析
函数的复杂度如下:
函数 最坏情况 一般情况 描述
GENERATE-BSP-TREE O(n2 lg n) O(n2) n为场景中多边形的数量
DISTRIBUTE-SAMPLE-POINTS Q (np + xy) Q (np + xy) n为树中多边形的数量,p为树中典型点的数量,x和y为分割面的宽度和高度。
TRACE-VISIBILITY O(n2) O(n lg n), n为树中多边形的数量。
RADIOSITY O(n3) O(n2 lg n) n为树中patch的数量

在一般情况这一列中显示了算法通常所需运行的时间,对算法时间影响最大的是函数RADIOSITY,它使整个算法的复杂度趋向于O(n3)。

BSP技术详解3---有图有真相相关推荐

  1. 【H.264/AVC视频编解码技术详解】十九:熵编码算法(5)——H.264的CABAC(上):语法元素的二值化方法...

    <H.264/AVC视频编解码技术详解>视频教程已经在"CSDN学院"上线,视频中详述了H.264的背景.标准协议和实现,并通过一个实战工程的形式对H.264的标准进行 ...

  2. Linux磁盘阵列技术详解(二)--raid 1创建

    我在Linux磁盘阵列技术详解(一)里已经详细介绍了几种RAID磁盘阵列方式,原理以及创建raid 0 的详细步骤.那么这篇文档就着重讲解如何创建raid 1的技术: 步骤如下: ① 分区 同样我们还 ...

  3. 《Hadoop技术详解》一导读

    前 言 Hadoop技术详解 本书采用的约定 本书采用以下排版约定. 斜体 用于表明新的术语.URL.电子邮件地址.文件名和文件扩展名. 等宽字体 用于程序清单,正文段落中有关的程序元素,如变量及函数 ...

  4. 科普:5G网络关键技术详解

    不久前,中国华为公司主推的Polar Code(极化码)方案,成为5G控制信道eMBB场景编码方案.消息一出,在网络上就炸开了锅,甚至有媒体用"华为碾压高通,拿下5G时代"来形容这 ...

  5. zookeeper 分布式过程协同技术详解.pdf_阿里大牛耗时18个月整理这份ZooKeeper分布式详解文档...

    前言 摩尔定律揭示了集成电路每18个月计算性能就会增加一倍.随着信息的飞速膨胀,很多应用都无法依赖单个服务器的性能升级来处理如此庞大的数据量,分布式系统和应用越来越受到人们的青睐.分布式系统和应用不仅 ...

  6. Qtum量子链研究院:Plasma技术详解(下篇)

    Plasma的设计模型有两个主要的分支:Plasma MVP(Minimal Viable Plasma,最小可行的Plasma)和Plasma Cash.Plasma MVP的目标是为最基本的可用的 ...

  7. Python数据科学-技术详解与商业实践视频教程

    Python数据科学-技术详解与商业实践(八大案例) 网盘地址:https://pan.baidu.com/s/13QrR_5Er6LgWCWzSb7qOrQ 提取码:s7vw 备用地址(腾讯微云): ...

  8. 视频直播技术详解(8)直播云 SDK 性能测试模型

    <视频直播技术详解>系列之八:直播云 SDK 性能测试模型 牛小七2016年10月12日发布在 视频直播技术详解 七牛云于 6 月底发布了一个针对视频直播的实时流网络 LiveNet 和完 ...

  9. 视频直播技术详解(7)现代播放器原理

    <视频直播技术详解>系列之七:现代播放器原理 牛小七2016年9月29日发布在 视频直播技术详解 from: http://blog.qiniu.com/archives/7040 七牛云 ...

最新文章

  1. vim中如何按一个键就保存文件
  2. “Duke选择大奖”荟萃2009最具创新的Java技术应用
  3. 1、cocos2dx开发学习第一篇-项目工程的创建
  4. python 分类变量转因子变量_python – 将分类变量的Pandas DataFrame转换为具有计数和比例的MultiIndex...
  5. c语言倒置存放,c语言倒置
  6. Java实现用户头像上传(修改默认文件大小限制)
  7. 云图说丨不同区块链之间如何跨链交互?
  8. 虚拟资源拳王公社:做什么副业能最快赚到钱?虚拟副业是怎么赚钱的
  9. Matplotlib作业2
  10. linux 的常用命令---------第十一阶段(rpm、yum的仓库搭建)
  11. ‘ActiveX component can’t create object解决方法
  12. commons-fileupload 的详细介绍与使用
  13. 【协同任务】基于matlab蚁群算法多组群UAV协同任务路径规划【含Matlab源码 1578期】
  14. 英语字帖电子版可打印_一年级英语字母专项练习:含26个英文字母书写教学 可下载电子版...
  15. 领克车机2.0安装 app 方法,亲测有效
  16. Inno Setup 6.0.3+ 简体中文语言包
  17. 离线强化学习总结!(原理、数据集、算法、复杂性分析、超参数调优等)
  18. 盛世昊通全新升级,引领智慧新经济
  19. 电话销售话术模板有哪些 电话销售技巧
  20. Xinetd服务的安装与配置详解

热门文章

  1. Android WebView中使用loadData时出现的乱码问题解决办法
  2. elasticsearch的cross_fields查询
  3. SQL中Truncate的用法
  4. webpack 插件: html-webpack-plugin
  5. Monkey测试com.android.browser 发 生类似android.datab
  6. CentOS 6.4利用xampp安装bugfree3
  7. matlab 中 eps 的分析
  8. [导入]javascript身份证号码验证函数支持带x
  9. Vue项目实战09 : vue3.0实现点击切换验证码(组件)及校验
  10. android 自定义取色器,【Android自定义View】仿Photoshop取色器ColorPicker(二)