雾是什么.doc

上传人:cn****1 文档编号:548044407 上传时间:2023-12-26 格式:DOC 页数:8 大小:132.79KB
返回 下载 相关 举报
雾是什么.doc_第1页
第1页 / 共8页
雾是什么.doc_第2页
第2页 / 共8页
雾是什么.doc_第3页
第3页 / 共8页
雾是什么.doc_第4页
第4页 / 共8页
雾是什么.doc_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《雾是什么.doc》由会员分享,可在线阅读,更多相关《雾是什么.doc(8页珍藏版)》请在金锄头文库上搜索。

1、雾胡红丽2004-4-16雾是什么?它形状千变万化,行踪飘忽不定,时而给人带来缥缈如仙境般的感受,时而给人一种神秘莫测的感觉。其实,雾只是漂浮在空气中,由成千上万的小水滴组成的可见聚合体罢了。雾是这么常见的一种自然现象,相信大家都体会过。所以为了增加虚拟世界的真实感,在现在的3D游戏中大量运用雾化效果来营造气氛,增强场景的纵深感和距离感。其实,在游戏中运用雾效果的深层原因是为了掩盖硬件的不足。在绘制每一帧场景的时候,由于受到目前硬件的限制,只能绘制一定距离内的场景,在这个距离之外即后裁剪面(back clip plane)之后的部分是空白的。为了弥补这个缺陷,很多游戏采用雾来掩盖这些没有画出的

2、场景。那么,在游戏中是怎么产生这些雾的呢?最简单的是深度雾。它假设空间中雾无处不在,并且均匀分布。所以对于观察者而言,他所看到的雾的浓度与他和目标物之间的距离是一个简单的线性关系。距离越远雾越浓。但是距离的计算本身不是一件简单的事情,它一般要进行平方根的计算,这样的计算量对于游戏这种需要实时反馈的应用显然是太大了,所以需要进一步的简化。我们可以假设观测者处于一个无穷远的位置,这样,距离就可以用目标物体的Z值来表示。得到了雾的浓度,接下来我们需要确定观察到的雾的颜色。观察者为什么能看见雾呢?这是因为雾吸收一部分光线,同时又散射出自己本身的颜色。雾的浓度越大,它吸收目标物体的颜色越多,散射出自己的

3、颜色也越多。从直观上看,我们一般使用下面的式子来表示:C= Cm*(1-Af)+Cf*Af(1)其中,C代表观察到的颜色;Cm代表目标物原来的颜色;Cf代表雾的颜色;Af代表雾的浓度。我们已经知道如何计算雾的浓度和颜色,那么我们如何在计算机里真正产生雾呢?第一种可用的方法,也是目前运用的比较多的方法,就是Vertex Fog。把3D物体进行投影变换之后,用每个物体的顶点(Vertex)的Z值代表雾的浓度,用类似式一的式子计算并修改该顶点的颜色。这样我们就得到了一个充满雾的场景。但是如果3D模型的顶点不是很多,就会出现不精确的情况。另外一种方法是fog table。所谓的fog table,就是

4、建立一张浓度和距离对应的关系表。在绘制场景时,对每一个象素(pixel),用其Z值在fog table 中查找对应的浓度,再进行fog的计算。这个方法的速度很快,因为在使用Z buffer时,每一个点的Z值已经算出,而且查表的速度也是很快的。这种方法的优点在于,因为是对每一个象素进行计算,所以无论模型的顶点多少都不会影响绘制效果。但是并不是所有的硬件都支持fog table,所以这种方法的使用受到了限制。Direct3D是支持fog table的。无论硬件是否支持fog table,它总会支持texture的。我们可以用1D的纹理来模拟fog table的效果,这就是纹理雾(texture f

5、og)。用纹理来模拟fog table有很多好处。首先,几乎所有的硬件都支持perspective corrected texture(在透视空间中正确做插值,需要双线性插值,如果不支持,纹理将会有明显的错误),但是很少有硬件支持perspective corrected color,所以vertex fog的效果常常不正确。其次,texture coordinate generation可以有很多种变形,不用Z值做雾的浓度,可以制作许多有趣的雾效果,例如即将要阐述的volume fog效果。用纹理来做雾也是有很多缺点的。最主要的缺点就是成本太高。在一个本身就需要多重纹理贴图(如使用了ligh

6、t map效果等)的场景中,再增加一层纹理,对硬件而言,往往需要一个额外的pass,这就需要更大的带宽。用1D的纹理做雾,还是有缺陷的。假设这样一种场景,观察者离雾很近,那么近处的雾应该比较淡一点,这样才符合现实的体验,但是用1D的纹理贴图不可能产生这种效果,因为这不是一种简单的线性关系,所以必须用2D甚至3D纹理才能制作出真正的雾效果。从上面的阐述可以看出,深度雾可以快捷的产生雾效果,复杂度比较低。但是这种整个场景都充满均匀分布的雾的模型显然无法体现真实生活中的各种现象,例如在一个熬药的大锅上面经常有大团的水蒸气,但是场景中别的地方可以没有。为了表现这些复杂的模型,我下面将仔细阐述体积雾的原

7、理。雾中包含着成千上万的小粒子,这些小粒子不仅吸收来自场景中的光线,他们还要反射一部分的光线回到场景中去,粒子之间还存在反射、散射、吸收等问题,要建立这样一个模型简直太复杂了。为了能在计算机中模拟出这样的雾模型,必要的假设是必须的。第一个假设:雾中的每一个粒子,无论它处于什么位置,它所吸收到的光线是相等的。第二个假设:雾中的每一个粒子,它所反射的光线也是等量的,并且向所有的方向进行反射。在这两个假设的前提下,给定一个球体雾,那么在所有的方向上将有等量的光线。我们用一个多面体来代替雾,用一束光线进出该多面体的点的w值的差值乘以某些常数来近似表示雾的浓度(从数学上说,这是stroke定理的简化形式

8、)。我们对每一个象素点都进行相同的计算。图示如下:图一:用B-A近似表示雾的浓度最简化的一个例子:让我们现在来看看一个简单的例子。我们要渲染一个不包含任何物体(相机也不包含在内)的凸多面体。为什么要强调是凸多面体呢?因为只有在这种情况下,一束光线进出多面体的次数才不会大于两次。那么如何计算每一个进出的象素点呢?我们先渲染fog volume的正面,读取该点的w值作为A值。然后改变三角形的缠绕方向,再次渲染fog volume,读取该点的w值作为B值,B-A即为屏幕上该象素点的雾的浓度。对屏幕上每一个象素点都进行相同的计算,用A buffer存储前面(A点)的值,用B buffer存储背面的值,

9、从B buffer中减去A buffer的值,留下的就是屏幕上所有象素点的雾的浓度值。如何进行w值的操作呢?vertex shader把w值编码进alpha管道,所以我们可以把每一个pixel的值编码进alpha管道,相减后剩下的值就代表该pixel的雾的浓度值。图示如下:图二:前面、后面以及差值在本例中,算法可以描述如下:1、 渲染fog volume的背面到一个后台缓冲区,用每一个pixel的w值代替alpha值。2、 用相同的编码方式渲染该fog volume的正面,并且用新的alpha值去减后台缓冲区中的alpha值。3、 用后台缓冲区中留下的alpha值作为雾的浓度值进行后续处理。f

10、og volume中包含物体的例子:在实际的例子中fog volume一般包含有物体。在这种情况下,如果继续按照上面的算法进行渲染,则会出现比较明显的错误,如下图所示:图三:左边是错误的情况,右边是正确的情况出现错误的原因是很明显的。因为此时fog volume的背面已不再是我们所定义的fog volume的背面,而是物体的前表面,我们还按照先前定义的后表面进行渲染,计算出的雾的浓度自然就不正确了。解决这个问题可以利用一个小技巧。先渲染包含物体的场景,打开深度测试,然后渲染fog volume的背面,如果某个pixel位于物体的后面,则被抛弃,物体该点则成为fog volume的后表面。算法描

11、述如下:1、 清空缓冲区。2、 激活深度测试,渲染整个场景(包含所有的物体)到后台缓冲区A,用每个pixel的值代替该pixel的alpha值。3、 在激活深度测试的条件下,渲染fog volume的背面到同一个缓冲区A。因为打开了深度测试,所以深度测试失败的pixel被抛弃,物体前表面成为fog volume的实际后表面。4、 渲染fog volume的前表面,用得到的w值去减缓冲区A中对应的值。5、 用缓冲区A中的alpha值作为雾的浓度值进行后续处理。fog volume包含一部分物体的情况:前述的算法还存在一个缺点。当fog volume没有全部包含整个物体的时候,不在fog volu

12、me中的部分物体也被渲染到了后台缓冲区,这导致原本没有雾的地方也被雾笼罩了。我们可以用stencil buffer来解决这个问题,但是这里想讨论另外一种方法。在刚才叙述的算法中,我们用渲染场景的方式来正确渲染fog volume的后表面,这里我们可以利用同样的技巧来正确渲染fog volume的前表面,算法描述如下:1、 清空缓冲区。2、 渲染场景到后台缓冲区A,用每个pixel的w值代替该pixel的alpha值。激活深度测试。3、 用相同的编码方式渲染fog volume的背面到缓冲区A。4、 渲染场景到后台缓冲区B(或者在第三步之前拷贝A中的值)。5、 渲染fog volume的前表面。

13、因为打开了深度测试,所以物体位于fog volume之后的点被fog volume上的点替代。6、 用B减去A得到的值作为雾的浓度值进行后续处理。相机在fog volume中的情况:我们前面讨论的都是相机在fog volume外的情况,如果相机移动到fog volume内部,这时的情形是什么样的呢?由于相机在fog volume内部,这导致fog volume的前表面被剔除,上述算法的第五步失效(因为fog volume的前表面已经被剔除)。最后渲染的结果是不正确的,场景中有的地方有雾,有的地方本该有点雾的现在一点雾也没有。解决这个问题的方法也很简单。前面算法的第四步是因为物体部分处于雾中而添

14、加的。当相机处于雾体中的时候,所有的物体都处于雾中,所以第四步可以完全跳过。下面是渲染凸多面体雾的一个通常的算法:1、 清空缓冲区。2、 渲染场景到后台缓冲区A,用每个pixel的w值代替alpha值,激活深度测试。3、 渲染fog volume的背面到缓冲区A。4、 如果相机在fog volume体外,则渲染场景到后台缓冲区B中(或者在第三步之前从A中拷贝),否则,跳过这一步。5、 渲染fog volume的前面到缓冲区B中,如果第四步执行了,则fog volume的前表面将代替物体处于fog volume后面的点,如果第四步没有执行,则这一步的执行效果被忽略,因为fog volume的前表

15、面已经被剔除。6、 用B减去A得到的值作为雾的浓度值进行后续处理。进一步的优化:前面所述的是一些基本的雾模型。有很多种方法可以进一步优化。讨论最多的应该是如何提高精度。现阶段的硬件的alpha管道只有8位,这限制了某些应用,如铺满整个地面的一大片雾。解决方法之一就是本文开始提到的纹理雾。用1D的纹理模拟fog table,每个纹元可以包含更高的精度。这种方法受到纹理大小的限制。当精度的问题解决后,我们就可以在现有8bit的机器上渲染凹多面体雾。第一种方法是把凹多面体分割成一系列的凸多面体进行渲染,第二种方法是累加进入的点去减出去的点。后一种方法由于受限于pixel shader而很难实现。下面

16、进一步阐述如何在8bit的alpha管道上获得更高的精度进行凹多面体的渲染。凹多面体的处理:在凸多面体的情况下计算进出fog volume的距离是非常简单的,但是对于凹多面体就不行了,因为一束光线有可能进出fog volume两次以上。解决方法如下图所示:图四:(B1-A1) + (B2-A2) (B2+B1)-(A2+A1)从上图可以直观的看出,这相当于把一个凹多面体分割成了一系列凸多面体,然后进行相加。8bit的精度是不够的,每增加一位的精度可以增加一次加减法运算,可以实现更复杂的雾体。在这里,凹多面体有一个前提限制。它必须是连续的、方向性的体,即不允许这个体中有孔(洞)。换句话说,一束光线进入体n次,出来也是n次。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号