游戏开发论坛

 找回密码
 立即注册
搜索
查看: 11801|回复: 18

光能传递 算法

[复制链接]

21

主题

125

帖子

135

积分

注册会员

Rank: 2

积分
135
QQ
发表于 2006-7-18 23:52:00 | 显示全部楼层 |阅读模式

  <光能传递> 2006 -7-18


-- 原由---------------------
      嘻,最近在VR网站看了一个Quest3D_Demo之后,想做室内虚拟实现程序,哈,想把自己的房间真实的渲染出来,但遇到的麻烦就是光影问题。我首先做了一个简单的室内模型,使用 3DsMax 7.0 光能传递渲染,嘻,效果是不错,但速度慢,没有办法,光能传递算法现在还没有很完美的。做完3DsMAx渲染后,使用“渲染到纹理 Render To Texture”,选择 “烘焙对象” 计算出来 Lightmap,哈,这样做是我一向的做法,再使用 Lightmap ,这样的光影数据看起来真实,并程序运行速度快。但很麻烦,对于大的场景这样做有点不实际。后来看到网上一个“Light Map Maker”工具。里面也有光能传递计算,并生成纹理。但我还是觉得不喜欢,别人的东西。很不开放,靠它的。还要注册使用。
      于是自己做光能传递,这是一个很有意思的。哈,可能会使我们学习到更多的知识。于是我找光能传递算法。
      找资料是很重要的,没有必要说自己闭门研究,要是那样真的是个傻瓜。
      在 google 里输入“光能传递”回车,看到的确绝大都是关于 3DsAMx 渲染器的使用教程。中国网上对于这个的介绍真的很少很少。这点我试了多个关键字搜索都搜索不了。两个字形容“落后”,我只能感叹中国的教育。于是输入英文"Radiosity",在 google 里搜索,找到的确是很多我真正有用的资料。代码可能没有多少,但 PDF 理论文章真的很多,看都看不来,我这里找到了几个很好的教程。但算法没有很仔细的说。没有关系,有原理描述就可以了。哈,国外的东西真的很多值得我们中国人去学习的。要不让我们和别人的距离真的越来越大,说到这里,我还是只能感叹中国教育方式。大学我们学习到了什么?
      费话少说,我们开始学习怎么去做光能传递。

(由于个人水平有限,说错了请原谅)
(部分文字引用)

-- 联系---------------------
QQ:444163200
E-mil/ MSN:GreenLitchi@163.com
Guangzhou / Zhuhai, China
大二学生



-- Radiosity 光能传递是什么?---------------------
没有光,我们眼睛将什么都看不到。在高中物理学中,光,是什么?1905年爱因斯坦提出了著名的光电效应,认为紫外线在照射物体表面时,会将能量传给表面电子,使之摆脱原子核的束缚,从表面释放出来,因此爱因斯坦将光解释成为一种能量的集合——光子。
      要是你还不理解光是什么,去这个网站看看。
http://www.ssrf.ac.cn/6/6.1.htm

      我们之所以看到物体有不同的颜色,是因为物体表面属性决定了物体吸收一定波长的光能,而不吸收的一部分反射到我们的眼睛里,产生了颜色。如果一束全波段光波射到一白色物体和红色物体上(两物体靠近,都是漫反射面),则白色物体并不吸收任何可见波波长的光能(理论上,实际上它还是要吸收一部分),把接收的光能都反射出去。那么红色物体就吸收了除红色波长以外的所有可见光光能,把红色波长的光能反射出去。这样,白色物体从环境中获得的光能发生了不平衡,红色光波的能量战多数,于是,在实际中的以上情况,我们将看到两物体之间发生了光能传递。
还有一个例子,就是镜子。因为漫反射面十分粗糙,几乎每个点的法线都不同,所以光能发射的方向不一,就造成了辐射现象;而非漫反射面表面法线一致,所以光能反射方向一致,所有光能向同一方向反射,造成镜面现象。要注意的是,生活中我们是在一个封闭的空间中观察物体的,就算是户外,因为空气有散射作用,所以也可以算是封闭。就是在一定范围内光能必须趋向平衡。所以几乎所有的光能传递演示场景都是在封闭的室内,而室外的场景则必须添加大气辐射。Lightscape中的完成百分比实际是它估算的环境内辐射平衡残差(以后会讨论),但也可以看作是封闭环境中剩余的未平衡能量。光能传递分成四种类型:漫反射~漫反射、非漫反射~漫反射、非漫反射~非漫反射、漫反射~非漫反射。这四种传递性质各异,难以以统一的算法求解,也导致了两种完全不同的算法的产生。
      1984年美国Cornell大学和日本广岛大学的学者分别把热力学中的辐射度方法引入到了光能传递求解当中,成功地模拟了漫反射面之间的光能传递。于是Radiosity算法问世了。
      光能与热能的性质十分相似,可以说光与热是能量的两种表现方式,光在理想漫反射面上的传递方式与热力学的辐射方式近似。因为热是向热力不均匀的地方传递的,而光也是向光能不平衡的地方传递的;而热力辐射的方式是扩散的,光能在漫反射面上的反射也可以近似表示为扩散。
Radiosity是在80年代末发展起来的渲染算法,它采用热力学的辐射积分式:
B(x)=E(x)+p(x)$B(x')[cos(x)cos(x')/pi*r^2]*HID(dS(x),dS(x'))dA(x')
其中x'为源元面,x为目标元面,B(x)是x的辐射度分量,E(x)是x的源能量,p(x)是x的漫反射系数,$是对元面x积分,HID是遮挡函数(x与x'之间有遮挡为0,没有则为1),dA(x)是x的面积。可以看到,Radiosity是通过对整个场景的表面都求解辐射度来达到模拟光能传递效果。
-- 简单描述原理 和 一般算法------------------

1. 当我们建立一个场记后,没有灯光的条件下,我们将看不到任何物体,一片黑色。




2. 在场景中所有物体,我们将认为是有无数个三角形组成。

3. 对于这个三角形,我们分割它们, 得到最小可视单位,我们叫它为:patch(哈,我没有听过他的中文意思,直接翻译的话叫:碎片/小块地/斑纹)。





3.我们从一个小patch中观看场景,哈,有意思,我们将看到这样的场景。




4. 接着,我们设置太阳的位置,在这个patch上看到一个小亮点。




5. 我们开始把灯光照射patch 上面,这样看来,没有看待太阳的patch将是黑的,看到太阳的patch将是白色。







6. 当我们把所有的小 patch 都照射处理后,将再通过patch看场景,这时候看到的是:




7. 我们通过这个看到图片再照色回我们原来的小 patch。

8.经过一次的计算后,我们将看到的是:



9. 看起来已经接近向真实迈出第一步。
10. 我们再次循环patch照射整个场景。第四次后:



11. 处理第 16 次后:





-- patch 光能计算 ------------------------------
1. 在 patch 中看到的场景入图:




我们把它做成这样方型的盒子:



张开它:





在计算之前,我们要理解,在我们侧面的光将比正面的光照射能量少。所有减弱它。
使用这个 正弦或余弦图处理。这个图的计算方式,等下面介绍到。








代码和实现 ----------------------------------------------
      嘻,为不让大家失望,我附加上自己源代码。
      这里有两点要说明,这个是VC++ 6.0 代码,在这个之前,国外的有个使用 Borland Delphi 语言实现这个功能,我完全模范它,并重新使用VC++改写代码。具体的功能,你们可以上网去找有关这个 Delphi 语言实现的代码。感谢这个作者 Georgy Moshkin 为我们所做出来的贡献,也感谢自己辛苦地改写完代码。花了 5 个小时,哈,我完全没有学习过 Delphi 语言,但一看就知道它每句代码意思,包括标识符号,哈哈,老实说(别见笑):学习过C语言的人,很容易精通其它语言。别老是追求语言的潮流,今天看来学习JAVA的人真的很多,但我真的真的真的不认为JAVA比C++好,而且它在跨平台上,我觉得比不上C语言。靠它的JAVA。哈,Delphi 语言真的很像VB但又像VC,哈,很有意思。我想做这语言的天才,一定都像很喜欢VC和VB,包括汇编。
        再次感谢 Georgy Moshkin.
      Georgy Moshkin 所写的 Delphi 语言实现代码,下载地址:
http://www.xp108.com/


      哈,大家放心,可以编译通过,我也下载了 Delphi 7 安装试过了。真的不错。


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Radiosity 光能传递 by Litchi
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我程序和VC++ 版本的代码附加上。
sf_2006718235142.jpg

21

主题

125

帖子

135

积分

注册会员

Rank: 2

积分
135
QQ
 楼主| 发表于 2006-7-18 23:53:00 | 显示全部楼层

Re: 光能传递 算法

设置高度为 -19.0f 后,渲染画面
sf_2006718235251.jpg

21

主题

125

帖子

135

积分

注册会员

Rank: 2

积分
135
QQ
 楼主| 发表于 2006-7-18 23:59:00 | 显示全部楼层

Re: 光能传递 算法

VC++ 代码入下:

sf_200671823590.rar

115.78 KB, 下载次数:

21

主题

125

帖子

135

积分

注册会员

Rank: 2

积分
135
QQ
 楼主| 发表于 2006-7-19 00:01:00 | 显示全部楼层

Re: 光能传递 算法



这个图是我使用VC控制台中保存 BMP数据后得到的。
VC++代码如下:

int picWidth = 32;
int picHeight=32;

        struct strRGB{
                unsigned char        R;
                unsigned char        G;
                unsigned char        B;
        };
        strRGB bufdata[picWidth][picHeight];

        float k;
        for(long x=0; x<picWidth; x++){
                for(long y=0; y<picHeight; y++){

                        k = 0.5+0.5*sin( x*3.14/(picWidth-1) )*sin( y*3.14/(picHeight-1) );
                        k = (k-0.5)*255.0f;

                        bufdata[x][y].R = k;
                        bufdata[x][y].G = k;
                        bufdata[x][y].B = k;
                }
        }


对了,有一点非常重要,差点忘记说了,这个程序都是使用GPU绘制出来的,依靠我们的显示卡绘制。图像的真实度不大。但很值得我们搞图形软件们的研究,哈哈。对于完全使用 CPU 计算出来的光能传递算法,大家可以上网去找找资料,最好是在 google 那里搜索。

有兴趣的可以一起交流交流。我们需要不断向上的学习。哈。
(要是有不妥地方,再次表示原谅,个人水平有限)
sf_20067190055.jpg

32

主题

1259

帖子

1351

积分

金牌会员

Rank: 6Rank: 6

积分
1351
发表于 2006-7-19 08:58:00 | 显示全部楼层

Re:光能传递 算法

感谢楼主提供源代码,要好好研究一番了。

30

主题

357

帖子

388

积分

中级会员

Rank: 3Rank: 3

积分
388
QQ
发表于 2006-7-19 09:43:00 | 显示全部楼层

Re:光能传递 算法

楼主真无私!感谢!

21

主题

125

帖子

135

积分

注册会员

Rank: 2

积分
135
QQ
 楼主| 发表于 2006-7-19 09:56:00 | 显示全部楼层

Re:光能传递 算法

哈哈, 我准备改写代码,由于这个程序在计算 patch 的时候,它使用显示卡绘制.速度我想还算可以.依靠CPU和GPU一起计算。我在网上看到了一个叫“Radiosity on Graphics Hardware”。就是利用图形卡来计算光能传递方法,哈,但我要仔细看它的内容才知道怎么回事。我想和这个的原理差不多。
我还看到了一个叫“real-time”的呢,哈哈,厉害。但它渲染出来的画面不太好真实。

接下来,我想用它去处理更加复杂的场景试试,又要重新改写代码。
希望有兴趣的可以一起研究研究。

21

主题

125

帖子

135

积分

注册会员

Rank: 2

积分
135
QQ
 楼主| 发表于 2006-7-19 10:24:00 | 显示全部楼层

Re:光能传递 算法

对了,要是在本程序提高渲染质量的话,可以调节光图大小,这里就是 patch 的个数了,哈,也是 3DsMAX 里面说的"网格"大小.

在本程序修改方法:
在int InitGL(GLvoid)函数里,你们可以看到 myLightmap.makeBMP(        8, 8,0,0,0);
那那里的 8 ,8 修改为 16, 16 ,这样的话效果话更好点,但是计算完成速度也慢点.
有付出才有收获嘛.

5

主题

686

帖子

697

积分

高级会员

Rank: 4

积分
697
QQ
发表于 2006-7-19 22:06:00 | 显示全部楼层

Re:光能传递 算法

PRT也是用辐射度方程来计算光照,不过它需要预计算把光源和传输函数投影到SH或小波,LZ通过多次循环Patch来计算场景,是不是为了让光传收敛达到平衡态?每次迭代都是用GPU?不需要预计算吗?

0

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2006-7-20 01:36:00 | 显示全部楼层

Re:光能传递 算法

日,从网上抄来的例子程序怎么就成了你的了? 无耻啊,做游戏谁没看过这个例子程序啊?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-8 09:56

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表