辐射度算法(radiosity)原理
简单地说,辐射度算法就是:把场景细分到很细很细的面片(如1个像素那么大的三角形),分别计算它们接受和发出的光能,然后逐次递归,直到每个面片的光能数据不再变化(或者到一定的阀值)为止.因此,计算量很大(要计算很多次),而且难以并行(因为递归)
Hugo Elias
何咏 译
声明:本文原文由Hugo Elias 撰写,由何咏 翻译。本文仅供学习交流之用。
任何人未经本人同意不得私自转载,任何人不得将本文用于任何商业活动。
简介:这篇文章是一个经典的辐射度算法的教程,详细的讲述了如何通过辐射度算法为静态场景计算光照贴图。这也是大多数游戏所采用的技术。现在很多的论文和书籍都讨论了如何在实时渲染中应用光照贴图来产生逼真的光照效果,然而他们主要着重于如何组织光照贴图。而光照贴图究竟是怎样计算出来的,也就是全局照明算法,却极少有资料进行详细的解释。我在网上搜索到这篇文章,看了之后受益匪浅,于是决定将它翻译出来,让更多的人了解这方面的知识。如果对这篇文章有不理解的地方,可以联系作者,也可以和我共同讨论( 我的网站:http://program.stedu.net ) 。如果翻译有错漏,也敬请指正和谅解,因为这毕竟是本人第一次翻译文章。如果你的英文水平不错,建议直接看原文: 单击这里
光照和阴影投射算法可以大致地分为两大类:直接照明和全局照明。许多人都会对前者较为熟悉,同时也了解它所带来的问题。这篇文章将首先简要地介绍两种方法,然后将深入地研究一种全局照明算法,这就是辐射度。
直接照明
直接照明是一个被老式渲染引擎( 如3D Studio 、POV 等) 所采用的主要光照方法。一个场景由两种动态物体组成:普通物件和光源。光源在不被其他物件遮挡的情况下向某些物件投射光线,若光源被其他物体遮挡,则会留下阴影。
在这种思想之下有许多方法来产生阴影,如Shadow Volume( 阴影体), Z 缓冲方法,光线追踪等等。但由于它们都采用一个普遍的原则,因此这些方法都有同样的问题,而且都需要捏造一些东西来解决这些问题。
直接照明的优缺点:
|
需要考虑的最重要的问题是,由于这些方法会产生超越真实的图像,他们只能处理只有点光源的场景,而且场景中的物体都能做到完美地反射和漫反射。现在,除非你是某种富裕的白痴,你的房子可能并不是装满了完全有光泽的球体和点状的光源。事实上,除非你生活在完全不同的物理背景下的一个宇宙空间,你的房间是不可能出现任何超级锐利的阴影的。
人们宣称光线追踪器和其他渲染器 能够产生照片级 的真实效果是一件非常自然的事情。但想象如果有人拿一张普通光线追踪(这种渲染方法类似经典OpenGL 光栅和光照渲染方法)的图片给你看,然后声称它是一张照片,你可能会回敬他是一个瞎子或者骗子。
同时也应该注意到,在真实世界里,我们仍然能看到不被直接照亮的物体。阴影永远都不是全黑的。直接照明的渲染器 试图通过加入环境光来解决这样的问题。这样一来所有的物体都接受到一个最小的普遍直接照明值。
全局照明
全局照明方法试图解决由光线追踪所带来的一些问题。一个光线追踪器往往模拟光线在遇到漫反射表面时只折射一次,而全局照明渲染器 模拟光线在场景中的多次反射。在光线追踪算法里,场景中的每个物体都必须被某个光源照亮才可见,而在全局照明中,这个物体可能只是简单的被它周围的物体所照亮。很快就会解释为什么这一点很重要。
全局照明的优缺点
由全局照明方法产生的图片看起来真正让人信服。这些方法独自成为一个联盟,让那些老式渲染器 艰苦地渲染一些悲哀的卡通。但是,而且是一个巨大的“但是” :但是 它们更加地慢。正像你可能离开你的光线追踪渲染器一 整天,然后回来看着它产生地图像激动地发抖,在这儿也一样。
|
优点 |
缺点 |
辐射度算法: |
- 非常真实的漫反射表面光照 |
- 慢 |
蒙特卡罗法: |
- 非常、非常好的效果 |
- 慢 |
用直接照明照亮一个简单的场景 我用3D Studio 对这个简单的场景进行了建模。我想让这个房间看起来就像被被 窗外的太阳照亮一样。 因此,我设置了一个聚光灯照射进来。当我渲染它时,整个房间都几乎是黑色的,除了那一小部分能够被光射到的地方。 打开环境光只是让场景看起来呈现一种统一的灰色,除了地面被照射到的地方呈现统一的红色。 在场景中间加入点光源来展现更多细节,但场景并没有你想象中的被太阳照亮的房间那样的亮斑。 最后,我把背景颜色设为白色,来展现一个明亮的天空。 |
|
我用我自己的辐射度渲染器 来渲染这个场景。我用Terragen 渲染了一个天空盒来作 为光源,并把它放置与窗户之外。除此之外没有使用任何其他光源。 |
辐射度渲染器 的工作原理
清空你脑子里任何你所知道的正常的光照渲染方法。你之前的经验可能会完全地转移你的注意力。
我想询问一个在阴影方面的专家,他会向你解释所有他们所知道的关于这个学科的东西。我的专家是在我面前的一小片墙上的油漆。
Hugo: " 为什么你在阴影当中,而你身边的那一片跟你很相像的油漆却在光亮之中?"
油漆: " 你什么意思?"
Hugo: " 你是怎么知道你什么时候应该在阴影之中,什么时候不在? 你知道哪些阴影投射算法?你只是一些油漆而已啊。"
油漆: " 听着,伙计。我不知道你在说什么。我的任务很简单: 任何击中我的光线,我把它分散开去。"
Hugo: " 任何光线?"
油漆: " 是的。任何光线。我没有任何偏好。"
因此你应该知道了。这就是辐射度算法的基本前提。任何击中一个表面的光都被反射回场景之中。是任何 光线。不仅仅是直接从光源来的光线。任何光线。这就是真实世界中的油漆是怎么想的,这就是辐射度算法的工作机制。
在接下来的文章中,我将详细讲解怎样制作你自己的会说话的油漆。
这样,辐射度渲染器 背后的基本原则就是移除对物体和光源的划分。现在,你可以认为所有的东西都是一个潜在的光源。任何可见的东西不是辐射光线,就是反射光线。总之,它是一个光的来源,一个光源。一切周围你能看到的东西都是光源。这样,当我们考虑场景中的某一部分要接受多少光强时,我们必须注意把所有的可见物体发出的光线加起来。
基本前提:
1: 光源和普通物体之间没有区别。
2: 场景中的一个表面被它周围的所有可见的表面所照亮。
现在你掌握这个总要的思想。我将带你经历一次为场景计算辐射度光照的全过程。
一个简单的场景我们以这个简单的场景开始:一个有三扇窗户的房间。这里有一些柱子和凹槽,可以提供有趣的阴影。 它会被窗外的景物所照亮,我假设窗外的景物只有一个很小、很亮的太阳,除此之外一片漆黑。 |
现在,我们来任意选择一个表面。然后考察它上面的光照。 |
由于一些图形学中难以解决的问题,我们将把它分割成许多小片( 的油漆) ,然后试着从他们的角度来观察这个世界。 从这里开始,我将使用面片 来指代“一小片油漆”。
|
选取他们之中的一个面片。然后想象你就是那个面片。从这个角度,这个世界看起来应该是什么样子呢? |
一个面片的视角将我的眼睛贴紧在这个面片之上,然后看出去,我就能看见这个面片所看见的东西。这个房间非常黑,因为还没有光线进入。但是我把这些边缘画了出来以方便你辨认。 通过将它所看见的所有光强加在一起,我们能够计算出从场景中发出的所有能够击中这个面片的光强。我们把它成为总入射光强 。 这个面片只能看见房间以及窗外漆黑的风景。把所有的入射光强加起来,我们可以看出没有光线射到这里。这个面片应该是一片黑暗。 |
一个较低处的面片的视角选择柱子上的一个稍低一些的面片。这个面片能够看到窗外明亮的太阳。这一次,所有的入射光强相加的结果表明有很多的光线到达这里(尽管太阳很小,但是它很亮)。这个面片被照亮了。
|
墙拄上 的光照为墙拄上 的每个面片重复这个过程,每次都为面片计算 总入射光强之后,我们可以回头看看现在的柱子是什么样子。 在柱子顶部的面片,由于看不见太阳,处在阴影当中。那些能看见太阳的被照得很亮。而那些只能看见太阳的一部分的面片被部分地照亮了。 如此一来,辐射度算法对于场景中的每个其他的面片都用几乎一样的方式重复。正如同你所看到的,阴影逐渐地在那些不能看见光源的地方显现了。 |
整个房间的光照: 第一次遍历为每个面片重复这个过程,给我门带了 这样的场景。除了那些能够从太阳直接接受光线的表面这外,所有的东西都是黑的。 因此,这看起来并不像是被很好地照亮了的场景。忽略那些光照看起来似乎是一块一块 的效果。我们可以通过将场景分割为更多的面片来解决这个问题。更值得注意的是除了被太阳直接照射的地方都是全黑的。在这个时候,辐射度渲染器 并没有体现出它与其他普通渲染器 的不同。然而,我们没有就此而止。既然场景中的某些面片被照得十分明亮,它们自己也变成了光源,并且也能够向场景中的其他部分投射光线。 |
在第一次遍历之后面片的视角那些在上次遍历时不能看见太阳而没有接受到光线的面片,现在可以看到其他面片在发光了。因此在下次遍历之后,这些面片将变得明亮一些。 |
整个房间的光照: 第二次遍历这一次,当你为每个面片计算完 入射光强之后,上次全黑的面片现在 正被照亮。这个房间开始变得有些真实了。 现在所发生的是太阳光照射到表面之后反射一次时,场景的效果。 |
整个房间的光照:第三次遍历第三次遍历产生了光线折射两次的效果。所有的东西看起来大致相同,只是轻微的亮了一些。 下一次遍历也仅仅时 让场景更加明亮,甚至第16 次遍历也并没有带来很大的不同。在那之后已经没有必要做更多的遍历了。 辐射度过程 集中在一个光照解决方案上缓慢地进展。每一次遍历都给场景带来一些轻微地变化,直到产生的变化趋于稳定。根据场景复杂度的不同,以及表面的光照特性,可能需要几次或几千次遍历不等。这取决于你什么时候停止遍历,告诉它已经完成了。 |
第四次遍历 |
第十六次遍历 |
更加详细的算法描述: 面片
辐射光强(Emmision)
尽管我曾说过我们应该认为光源和普通物体是一样的,但场景中显然要有光发出的源头。在真实世界中,一些物体会辐射出光线,但有些不会。并且所有的物体会吸收某些波段的光。我们必须有某种方法区分出场景中那些能够辐射光线的物体。我们在辐射度算法中通过辐射光强来表 述这一点 。我们认为,所有的面片都会辐射出光强,然而大多数面片辐射出的光强为0 。这个面片的属性称为辐射光强(Emmision) 。
反射率(Reflectance)
当光线击中表面时,一些光线被吸收并且转化为热能( 我们可以忽略这一点) ,剩下的则被反射开去。我们称反射出去的光强比例为反射率(Reflectance) 。
入射和出射光强(incident and excident lights)
在每一次遍历的过程中,记录另外两个东西是有必要的: 有多少光强抵达一个面片,有多少光强因反射而离开面片。我们把它们称为入射光强和出射光强。出射光强是面片对外 表现的属性。当我们观看某个面片时,其实是面片的出射光被我们看见了。
incident_light(入射光强)= sum of all light that a patch can see
excident_light(出射光强) = (incident_light *reflectance ) + emmision
面片的数据结构
既然我们了解了一个面片的所有必要属性,我们就应该定义面 片的数据结构了。稍后,我将解释这四个变量的细节。
structurePATCH
vec4 emmision
float reflectance
vec4 incident
vec4 excident
endstructure
我已经讲解了算法的基础,下面将再次使用伪代码的形式加以讲解,让它更加具体。很显然这还是在一个较高的层次上,但我会在后面讲述更多的细节。
辐射度算法 伪代码: 级别 1
load scene
divide each surface into roughly equal sized patches
initialise_patches:
for each Patchin the scene
if this patchis a light then
patch.emmision= some amount of light
else
patch.emmision= black
end if
patch.excident= patch.emmision
end Patchloop
Passes_Loop:
each patch collects light from the scene
for each Patchin the scene
render the scene from the point of view of this patch
patch.incident= sum of incident light in rendering
end Patchloop
calculate excident light from each patch:
for each Patchin the scene
辐射度算法(radiosity)原理相关推荐
- 转:辐射度算法(radiosity)原理
转:辐射度算法(radiosity)原理 http://blog.sina.com.cn/s/blog_537cc4d90101iiil.html 简单地说,辐射度算法就是:把场景细分到很细很细的面片 ...
- 3d游戏开发――辐射度算法
Hugo Elias 何咏 译 声明:本文原文由Hugo Elias 撰写,由何咏 翻译.本文仅供学习交流之用. 任何人未经本人同意不得私自转载,任何人不得将本文用于任何商业活动. 简 介:这篇文章是 ...
- 计算机图形学【GAMES-101】11、渲染前沿技术介绍(双向路径追踪BDPT、MLT、光子映射、实时辐射度、外观建模)
快速跳转: 1.矩阵变换原理Transform(旋转.位移.缩放.正交投影.透视投影) 2.光栅化(反走样.傅里叶变换.卷积) 3.着色计算(深度缓存.着色模型.着色频率) 4.纹理映射(重心坐标插值 ...
- 文本相似度bm25算法的原理以及Python实现(jupyter notebook)
今天我们一起来学习一下自然语言处理中的bm25算法,bm25算法是常见的用来计算query和文章相关度的相似度的.其实这个算法的原理很简单,就是将需要计算的query分词成w1,w2,-,wn,然后求 ...
- 视觉SLAM开源算法ORB-SLAM3 原理与代码解析
来源:深蓝学院,文稿整理者:何常鑫,审核&修改:刘国庆 本文总结于上交感知与导航研究所科研助理--刘国庆关于[视觉SLAM开源算法ORB-SLAM3 原理与代码解析]的公开课. ORB-SLA ...
- 字符串相似度算法——Levenshtein Distance算法
Levenshtein Distance 算法,又叫 Edit Distance 算法,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数.许可的编辑操作包括将一个字符替换成另一个字符,插入一 ...
- hash算法_到底什么是Hash?Hash算法的原理和实际应用讲解
提到hash,相信大多数同学都不会陌生,之前很火现在也依旧很火的技术区块链背后的底层原理之一就是hash,下面就从hash算法的原理和实际应用等几个角度,对hash算法进行一个讲解. 1.什么是Has ...
- raft算法mysql主从复制_Etcd raft算法实现原理分析
1.1 主要概念 要实现集群数据的一致性,节点在进行通信的时候必定需要遵守特定规则进行数据校验,而这些规则具体都是通过某些具有特定含义的属性来实现的.为了让对Raft 算法比较陌生的读者对算法的关键概 ...
- K-Means聚类算法的原理及实现
K-Means聚类算法的原理及实现[转] [转]http://www.aboutyun.com/thread-18178-1-1.html 问题导读: 1.如何理解K-Means算法? 2.如何寻找K ...
最新文章
- linux内核支持硬盘,Intel 10nm桌面版还是来了:Linux内核已支持
- SilverLight学习笔记--建立Silverlight自定义控件(5)--绑定动画效果
- Linux平台定时监控进程退出并自动重启的方法
- AT2390-[AGC016F]Games on DAG【状压dp,SG函数】
- 面向对象设计与构造第一次总结作业
- 里面的自带的字典在哪里_影视剪辑高清素材哪里找?4种方法教你,适合新手入门...
- js_DOM读写节点
- 嵌入式系统功能需求分析_机械管理系统如何物料需求分析
- mysql锁问题排查_Mysql死锁问题如何排查和解决?
- jpa怎么传参到in中_JPA 中 in 的方法 注意参数一定要是List
- linux 文件上传扫描_SecureCRT实现windows与linux文件上传下载
- windows 互斥量内核对象 Mutex
- 数组模拟栈解决括号匹配
- 浙江省计算机二级办公软件高级应用技术真题,浙江省计算机二级办公软件高级应用技术考试题库.doc...
- 新版的Eclipse(Oxygen)安装完Subversive后,现时无法自动安装SVN Connector,无论选择哪个都会自动关闭。
- CocosCreator代码混淆加密
- matlab瓶盖盖严检查,口服液瓶盖密封性的质量检测方法你知道吗?
- 仿写“跳一跳”微信小游戏
- 华硕天选3笔记本电脑WiFi功能消失
- 电脑小鸟壁纸怎么彻底删除?
热门文章
- 牧牛区块链培训,区块链在数字金融中的应用
- 《猿族崛起》动作捕捉技术及制作流程详解
- Change to survive
- Spring Cloud Netfilx Zuul : API网关服务
- 华工大学计算机基础题库,华工大学计算机基础多选题库.pdf
- android 虹软 例子,虹软免费人脸识别 Demo [Android]
- 【IO】SBIO,SNBIO,ANIO,AIO
- 优雅地实现Android主流图片加载框架封装,可无侵入切换框架
- oracle数据库字符集AL32UTF8修改为ZHS16GBK即从超集到子集
- 康耐视3D-DS1000相机图像采集流程