- 浏览: 1087426 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (695)
- 心情日记 (14)
- AS开发工具 (12)
- 文章转载 (99)
- AIR (5)
- 问题总结 (46)
- SWF格式 (7)
- 测试总结 (10)
- 外文资料 (9)
- 算法技术 (33)
- AS3常用开源库 (43)
- 源码范例 (102)
- FLEX (72)
- FLASH 优化 (33)
- 游戏开发 (49)
- 开发技术 (11)
- 工作应用 (34)
- AS3收集 (140)
- WebBase (0)
- 开发构想 (4)
- 设计模式 (2)
- 框架和框架范例 (19)
- RED5 (3)
- java开发 (3)
- JAVA (1)
- FLASH-3D (23)
- 3D (6)
- 书籍 (10)
- 业界信息资料 (3)
- C# (1)
- JavaScript (12)
- HTML5 (6)
- Flixel (1)
- D5Power RPG网页游戏引擎 (0)
- ColorMatrixFilter - 获得相应颜色的色调 函数 (0)
- Starling (0)
最新评论
-
老顽童203:
字体
水果忍者鼠标跟随特效制作[转载] -
hairball00:
[转] 放出超多的Flash组件源代码 -
he74552775:
flash AS3 RegExp简单功能用法(转) -
hanshuai1232000:
第四点,有利也有弊,等你做了大型的aprg,你就知道了
[转]位图数据内存优化 -
yangfantao:
太感谢
[转] 放出超多的Flash组件源代码
http://dev.gameres.com/Program/Visual/3D/Radiosity_Translation.htm
修正半立方体图像
|
这是一个三个同样大小的球体的视图。以90°的透视视角渲染,三个球距摄像机的距离相同,但由于透视变换的属性,在视图两边的物体被拉伸而占据了比中间的物体更大的屏幕面积。 如果这是半立方体正中间的图像,且三个球体都是光源,那么在图像边缘的物体投射到面片上的光线就会偏多。这会导致不精确性,因此我们必须修正这个问题。 如果你想用半立方体来计算总共的入射光强,并且仅将半立方体中的像素值都加起来,那些处在图像边缘的物体就会得到一个不公平的权重。这会向面片投射更多的光线。 为了弥补这一点,将图片边缘的像素变暗是有必要的。这样才能让所有的物体均匀地向面片投射光线。不管它们位于图像的那些位置,我不想完整地解释为什么,只想 告诉你这是怎样做的。 |
|
半立方体表面的像素应乘以摄影机方向和光线入射方向之间的夹角的余弦值。 左边的贴图用来弥补这个失真。 |
兰伯特的余弦定律
|
任何初学计算机图形学的人都应该知道兰伯特的余弦定律:表面的亮度正比于表面法线和光源方向的夹角的余弦值。因此,我们在这里也应该应用这个定律。这只是简单地将半立方体图像与相关系数相乘。 左边是一张应用了余弦定律的贴图。白色代表1.0,黑色代表0.0。 |
两者叠加:乘法贴图
|
现在注意了,这一点非常重要: 将两个贴图相乘得到了这个贴图。这个贴图对于产生精确的辐射度解决方案是必要的。它用来调节透视投影带来的失真,也包括了兰伯特的余弦定律。 创建了这个贴图之后,正中间的值应该是1.0,四周角落的值应该是0.0。在它可以使用之前,这个贴图必须被单位化。 也就是说,贴图中所有的像素值之和应为1.0。 方法如下: · 对乘法贴图中所有的像素求和 · 将每个像素的值除以这个和. 现在,贴图中心的像素值应远小于1.0。 |
计算入射光强
这个过程在场景中选取一个点(通常是一个面片),以及改点所在表面的法向量,然后计算所有到达该点的光强。
首先,算法使用RenderView函数渲染半立方体的5个面。这个过程的参数包括一个点,描述了摄影机应放在哪里,以及一个向量,描述了摄影机正前方向,还有一个参数告诉这个过程要渲染半立方体的哪个面。这5张图片存储在hemicube的结构里,记为H(下图的左列)。
一旦半立方体H被渲染完毕,它就与乘法贴图M相乘(下图中间列)。结果存储在半立方体R中(下图右列)。
之后,R中的所有像素值相加后除以半立方体的像素总数,这就得到了该点的入射光强。
procedure Calc_Incident_Light(point: P, vector:
N) |
|
对伪代码中的变量类型的说明
light: 用于存储光照强度,如:
structure light
float Red
float Green
float Blue
end structure
hemicube: 用于存储从某一点所观察到的场景。一个半立方体应包含5个图片,如之前所说明的那样,每个像素的类型都是light。对于乘法半立方体来说,所存储的并不是一个光照强度值,而是一些小于1.0乘法因子。之前已经说明。
structure hemicube
image front
image up
image down
image left
image right
end structure
camera: 如:
structure camera
point lens
vector direction
end structure
增加解决方案的精确度
你可能会自己想到,这种鬼东西似乎要很多的渲染过程。做这些东西使得处理器处在高强度状态。你当然是正确的。基本上你不得不渲染几千次带有纹理的场景。
所幸的是,这是一个自从黎明破晓的时候人们就在研究的问题了。自从光栅显示器诞生的那一刻起,自从那个时候就有了关于如何快速渲染带有纹理的场景的许多工作。我不会在这一方面走得太深,我确实不是一个最具资格的人来讨论如何优化渲染过程。我自己的渲染器是如此的慢以致于你会用诅咒的语言来描述它。算法本身很适合用3D硬件来加速,可是你必须做 一些额外的前期准备工作来让硬件渲染32位的纹理。
我即将讨论的速度优化方法不会关心具体的加速半立方体的渲染方法,但是会讨论如何减少半立方体的渲染次数。你会,也理应会注意到光照贴图看起来呈现一种低分辨率的块状,但不要怕,它们的分辨率可以根据你的需要进行调节。
|
看一些左边用红线标出的表面。光照效果基本上十分简单,有一个较亮的区域,还有一个不太亮的区域,两者之间有一条相当锐利的界线。要减少边缘的锐利程度,你一般情况下需要一个更高分辨率的光照贴图,因此必须渲染更多的半立方体。但是似乎并不 值得为那些较黑或较亮的区域计算过多的半立方体,处在这两个区域之中的面片的颜色几乎是一致的。但是在锐利的边缘附近多渲染一些半立方体会更加有价值,而对那些处在亮或暗区域之中的面片则不需要过于细分。 这是十分简单的。我即将讲述的算法将渲染少量的半立方体均匀地覆盖在表面上,然后在靠近边缘的区域渲染更多的半立方体,对于剩下的光照贴图纹素,仅用线性插值来填充。 |
|
算法: 在左下角你可以看见正在被创建的光照贴图。在它旁边,你能看到有些像素通过计算半立方体来确定,而有些通过线性插值来决定。 |
|
|
1:使用半立方体为每4个像素确定一个值. (左图红色的点) 这些像素在右图用表示. |
|
|
2: 遍历1: 检查相邻两个之间的值的差。如果这个差大于某个阈值,则为像素(左图绿色区域)单独渲染半立方体。否则像素的值由插值决定。 |
|
|
3: 遍历2: 检查位于四个像素中心的像素 。如果相邻的两个像素差别太大,为这个像素单独渲染半立方体,否则使用线性插值决定像素的颜色值。 |
|
|
4: 遍历 1: 如同第二步,只是空间缩小一半。 |
|
|
5: 遍历 2: 如同第三步,只是空间缩小一半。 |
|
你应该能够看到,在左边的图中,大多数光照贴图像素都是通过线性插值决定的。事实上,对于一个由1769个象素的光照贴图来说,仅有563个像素是通过渲染半立方体来决定的。而另外1206个像素是通过线性插值决定的。现在,由于渲染一个 半立方体需要非常长的时间,比起几乎不花费时间的线性插值,这个方法是速度提升了大约60%!
至此,这个方法还不是完美的。它偶尔会错过光照贴图上一些细节。但在大多数情况下它的结果是非常好的。有个简单的方法来捕获微小的细节,但我把它留给你自己去思考。
以下是伪代码,注释就不翻译了。
#### CODE EDITING IN PROGRESS - BIT MESSY STILL ####
float ratio2(float a, float b)
{
if ((a==0) && (b==0)) return 1.0;
if ((a==0) || (b==0)) return 0.0;
if (a>b) return b/a;
else return a/b;
}
float ratio4(float a, float b, float c, float d)
{
float q1 = ratio2(a,b);
float q2 = ratio2(c,d);
if (q1<q2) return q1;
else return q2;
}
procedure CalcLightMap()
vector normal = LightMap.Surface_Normal
float Xres = LightMap.X_resolution
float Yres = LightMap.Y_resolution
point3D SamplePoint
light I1, I2, I3, I4
Accuracy = Some value greater than 0.0, and less than 1.0.
Higher values give a better quality Light Map (and a slower render).
0.5 is ok for the first passes of the renderer.
0.98 is good for the final pass.
Spacing = 4 Higher values of Spacing give a slightly faster render, but
will be more likely to miss fine details. I find that 4 is
a pretty reasonable compromise.
// 1: Initially, calculate an even grid of pixels across the Light Map.
// For each pixel calculate the 3D coordinates of the centre of the patch that
// corresponds to this pixel. Render a hemicube at that point, and add up
// the incident light. Write that value into the Light Map.
// The spacing in this grid is fixed. The code only comes here once per Light
// Map, per render pass.
for (y=0; y<Yres; y+=Spacing)
for (x=0; x<Xres; x+=Spacing)
{
SamplePoint = Calculate coordinates of centre of patch
incidentLight = Calc_Incident_Light(SamplePoint, normal)
LightMap[x, y] = incidentLight
}
// return here when another pass is required
Passes_Loop:
threshold = pow(Accuracy, Spacing)
// 2: Part 1.
HalfSpacing = Spacing/2;
for (y=HalfSpacing; y<=Yres+HalfSpacing; y+=Spacing)
{
for (x=HalfSpacing; x<=Xres+HalfSpacing; x+=Spacing)
{
// Calculate the inbetween pixels, whose neighbours
are above and below this pixel
if (x<Xres) // Don't go off the edge of the Light Map now
{
x1 = x
y1 = y-HalfSpacing
// Read the 2 (left and right) neighbours from the Light Map
I1 = LightMap[x1+HalfSpacing, y1]
I2 = LightMap[x1-HalfSpacing, y1]
// If the neighbours are very similar, then just interpolate.
if ( (ratio2(I1.R,I2.R) > threshold) &&
(ratio2(I1.G,I2.G) > threshold) &&
(ratio2(I1.B,I2.B) > threshold) )
{
incidentLight.R = (I1.R+I2.R) * 0.5
incidentLight.G = (I1.G+I2.G) * 0.5
incidentLight.B = (I1.B+I2.B) * 0.5
LightMap[x1, y1] = incidentLight
}
// Otherwise go to the effort of rendering a hemicube,
and adding it all up.
else
{
SamplePoint = Calculate coordinates of centre of patch
incidentLight = Calc_Incident_Light(SamplePoint, normal)
LightMap[x1, y1] = incidentLight
}
}
// Calculate the inbetween pixels, whose neighbours are left and
right of this pixel
if (y<Yres) // Don't go off the edge of the Light Map now
{
x1 = x-HalfSpacing
y1 = y
// Read the 2 (up and down) neighbours from the Light Map
I1 = LightMap[x1,y1-HalfSpacing];
I2 = LightMap[x1,y1+HalfSpacing];
// If the neighbours are very similar, then just interpolate.
if ( (ratio2(I1.R,I2.R) > threshold) &&
(ratio2(I1.G,I2.G) > threshold) &&
(ratio2(I1.B,I2.B) > threshold) )
{
incidentLight.R = (I1.R+I2.R) * 0.5
incidentLight.G = (I1.G+I2.G) * 0.5
incidentLight.B = (I1.B+I2.B) * 0.5
LightMap[x1,y1] = incidentLight
}
// Otherwise go to the effort of rendering a hemicube,
and adding it all up.
else
{
SamplePoint = Calculate coordinates of centre of patch
incidentLight = Calc_Incident_Light(SamplePoint, normal)
LightMap[x1, y1] = incidentLight
}
}//end if
}//end x loop
}//end y loop
// 3: Part 2
// Calculate the pixels, whose neighbours are on all 4 sides of this pixel
for (y=HalfSpacing; y<=(Yres-HalfSpacing); y+=Spacing)
{
for (x=HalfSpacing; x<=(Xres-HalfSpacing); x+=Spacing)
{
I1 = LightMap[x, y-HalfSpacing]
I2 = LightMap[x, y+HalfSpacing]
I3 = LightMap[x-HalfSpacing, y]
I4 = LightMap[x+HalfSpacing, y]
if ( (ratio4(I1.R,I2.R,I3.R,I4.R) > threshold) &&
(ratio4(I1.G,I2.G,I3.G,I4.G) > threshold) &&
(ratio4(I1.B,I2.B,I3.B,I4.B) > threshold) )
{
incidentLight.R = (I1.R + I2.R + I3.R + I4.R) * 0.25
incidentLight.G = (I1.G + I2.G + I3.G + I4.G) * 0.25
incidentLight.B = (I1.B + I2.B + I3.B + I4.B) * 0.25
LightMap[x,y] = incidentLight
}
else
{
SamplePoint = Calculate coordinates of centre of patch
incidentLight = Calc_Incident_Light(SamplePoint, normal)
LightMap[x, y] = incidentLight;
}
}
}
Spacing = Spacing / 2
Stop if Spacing = 1, otherwise go to Passes_Loop
|
点光源
人们普遍认为辐射度算法不能很好地处理点光源。从某种程度上讲确实如此,但在真实场景中出现点光源几乎是不可能的。 我试过向场景增加点状物体作为光源,使它作为粒子像素(Wu-Pixel)被渲染。在渲染半立方体时,它们作为一个明亮的像素出现在渲染出来的图片上,因而向面片投射闪耀的光。它运行得基本正确,但是渲染出来的图像 会出现无法令人接受的假相。右图所示的场景被三个点状聚光灯所照亮,其中的两个光源位于柱子的背后,还有一盏光源位于图片左上角附近,方向指向照相机。场景从这个角度看起来良好,但如果摄影机来回移动,就会出现令人厌恶的假相。
|
|
你可以看到,在下方的图片里,出现了三条暗线。这看起来似乎是因为点光源在靠近半立方体边缘的地方就消失了。可能如果我的数学好些的话就不会这么糟糕,但我想就算那样也还是会有引人注意的赝像。 因此,与其将点光源渲染到半立方体中,你不如使用光线追踪,在面片和点光源之间投射光线。 |
|
发表评论
-
[其他] Unity3d::UML的::动画可视化快速参考系列
2011-05-22 20:07 1764http://bbs.9ria.com/viewthread. ... -
[转]辐射度算法(三) - GameRes.com
2011-04-10 19:24 1127http://dev.gameres.com/Program/ ... -
[转]辐射度算法(一) - GameRes.com
2011-04-10 19:19 1639http://dev.gameres.com/Progr ... -
[转] 整理出的一些3D文件格式文档
2011-02-28 22:46 1029DAE : http://www.khron ... -
左手坐标系 和右手坐标系的差异, DX是左手坐标系, OPENGL是右手坐标系
2011-02-17 15:19 8888左手坐标就是z轴向里 右手坐标就是z轴向外 用你 ...
相关推荐
/* 用遗传算法(GA)解决TSP(旅行商)问题 ...Blog: blog.gameres.com/show.asp?BlogID=1450&column=0 E-mail: starsftk@yahoo.com.cn ps:初学遗传算法,很多都不懂,程序还有很多不足,若你改进了别忘了告诉我 */
GIF文档 - 中文 详细 全面 希望对大家有帮助 GIF文档 - 中文 详细 全面 希望对大家有帮助 GIF文档 - 中文 详细 全面 希望对大家有帮助 GIF文档 - 中文 详细 全面 希望对大家有帮助
一种简单、快速、高效的多边形减面算法 - GameRes_com.mht 看看
- **售后服务**:解决玩家遇到的问题,提供技术支持和更新,维护游戏社区的活跃度。 ### 第三章:游戏的策划工作如何进行 3.1部分详细讨论了游戏策划的核心任务,包括确定游戏的题材、类型和风格: - **游戏题材*...
《Windows游戏编程快速入门》是面向初学者的一篇教程,旨在引导读者踏入游戏开发的世界。本文档主要通过实际操作步骤,介绍了如何使用Visual Studio 2003 .NET来创建一个简单的Windows游戏项目,以此来教授基本的...
- `计算几何算法概览 - GameRes_com.htm`:这可能是一个网页文档,提供计算几何的基本概念、常用算法的概述,以及在游戏开发中的应用。 - `e913ACM.pps`:可能是PowerPoint演示文稿,详细介绍了ACM竞赛中的计算...
- 2ccc.com.nfo:NFO文件通常包含有关软件或分享内容的作者信息和版权声明。 - 开发日志.txt:记录了项目开发过程中的笔记、进度和问题。 - res 文件夹:可能包含游戏的其他资源文件,如图片、声音等。 - Map 文件夹...
游戏脚本系统是一种在游戏中实现动态行为和交互的关键技术,它允许开发者通过编程语言来控制游戏逻辑,而无需深入到游戏引擎的核心代码。"游戏脚本系统的demo"是针对这一主题的一个示例,提供了实践操作的经验,尽管...
在网上看到一篇A*寻路算法的译文 http://data.gameres.com/message.asp?TopicID=25439 按此原理写了以下程序另外补充:1.此算法不是最短路径算法. 2.在实际应用中肯定还需要优化,以适合具体游戏. 3.(vb.net2005测试...
作品发布:http://data.gameres.com/showmessage.asp?TopicID=163262 如下为作品相关信息,如有转载,请详细标明如下相关信息,以示尊重!! ==================作品信息================== 名称:MetalMax 作者:...
编程新手真言,转自gameres
代码说明 ---------------------------------------------------- 这是一个Win32的窗口应用程序工程。 用于调试与游戏环境类似的非图象部分...该程序参考了www.gameres.com中的一个输入法例程,在此对原作者表示感谢。
本压缩包文件"**huluwa.rar_GBGM.m_c++ 锁_huluwa官网_www.huluwa.com**"可能与一个名为"Huluwa"的游戏或软件相关,它似乎使用了C++语言,并涉及到了互斥锁(Mutex)的概念。"GBGM.m"可能是项目中的一个模块或者类名...
- **GameRes**(http://www.gameres.com/): 游戏开发资源和技术交流的论坛。 - **17173**(http://www.17173.com/): 以游戏资讯为主的论坛,但也包含一定的游戏开发内容。 - **52RD**(http://www.52rd.com/): ...
《Parallel World》为网友dongch007原创的3D场景漫游示例Demo,内含天空、陆地、湖泊、植被、建筑、角色动画、UI及场景特效等诸多场景必备元素,...原帖地址:http://data.gameres.com/showmessage.asp?TopicID=131818
- www.pudn.com.txt:这个文件可能是从网站pudn.com下载资源的说明,可能提到了获取更多DirectShow开发相关资源的链接或信息。 - Include:这个目录应该包含了DirectX 9 SDK的头文件,供你的项目引用。 - Lib:这个...
String email = "example@example.com"; Matcher matcher = pattern.matcher(email); boolean isValid = matcher.matches(); ``` 在提供的压缩包文件中,我们可以看到几个可能与正则表达式解析库相关的文件: 1. `...
- **论坛**:[http://bbs.gameres.com/showforum.asp?forumid=99](http://bbs.gameres.com/showforum.asp?forumid=99) 以上资源为学习OGRE 3D提供了丰富的参考资料和技术支持。 #### 六、总结 《Pro.OGRE.3D....