《Pro Ogre 3D Programming》读书笔记 之 第十一章 动态阴影

《Pro Ogre 3D Programming》读书笔记 之 第十一章 动态阴影

清源游民  [email protected]

阴影技术
Ogre支持两种主流的动态阴影技术,模板(stencil)阴影与纹理(texture)阴影,每一种都有两个变体:modulative 与additive。这四种技术完全兼容固定函数图形流水线,因此不需要可编程GPU支持。然而,可利用GPU程序进行加速。在场景中只有使用一种阴影技术,应该在场景渲染这前进行阴影技术相关设置(最好是在创建场景管理器之间)。通过调用SceneManager::setShadowTechnique()来设置技术,参数指定技术的具体类型。阴影技术缺省情况下被关闭。对于物体,投射与接收阴影可以在材质中控制,也可以控制物体自己对自己投射。由于模板阴影算法的本质特征,透明半透明的物体要么全部投射实心阴影要么根本不投影影,不可能得到半透明的阴影。而使用纹理阴影技术则可以。灯不能用来投射阴影。
模板阴影算法
模板阴影算法原理上来讲比较简单:从光源的角度看一个可以投射阴影的物体,可以看到物体最外轮廓的
形状,把这个轮廓沿光的方向延伸,形成一个空间体,就是所谓的阴影锥(shadow volume),很显然,如果一
个物体被这个阴影锥包围,那么这个物体就处于前面那个物体所投射的阴影中了。既然阴影锥是通过延伸的方式来增长的,那么可以在延伸方向对锥体的延伸范围作出控制。在延伸方向上,有一端不能延伸,另外一端的延伸范围控制按照下面两个规则。第一,如果使用可编程图形硬件,顶点程序可以对顶点进行无限延伸。第二,如果使用固定函数图形流水线,延伸的范围由光线衰减设置(点光源和聚光灯)或使用
SceneManager::setShadowDirectionalLightExtrusionDistance()来控制。在不使用加速图形硬件的情况下,应该尽量避免物体离光源过近,这样会产生过于宽的阴影锥,导致不正确的阴影效果。根据算法原理,产生的阴影边界非常明显:一个像素要么在阴影中,要么不在。这带来的好处是,即使阴影锥的延伸距离很大,也不会影响精度。可以讲这种技术产生的阴影是一种“硬阴影"。纹理阴影技术可以”软化“阴影。使用模板阴影技术需要边列表(edge lists),标准的转换工具在产生二进制mesh文件时会创建边列表,如果没有,在程序中也可以用Mesh::buildEdgeList()来产生。因为有时候,我们会代码的方式来生成mesh,如果这时我们想使用模板阴影技术,那么就要确保产生出边列表数据。如果边列表数据不存在,那么ogre会认为你不希望这个物体投射阴影。
模板阴影优化
Ogre能进行一些一般的优化。例如可使用硬件加速,可能通过光的方向与范围来检测它是否会对平截头体
(frustum)产生影响,从面避免了计算那些不必要的阴影几何体。ogre支持双面模板,stencil-wrapping扩展,
这些都能阻止不必要的原型安装(primitive setup)与驱动过载(driver overhead)。ogre使用相对廉价的Z-pass算法代替Z-Fail算法(当Z-Fail算法不必要时,假如相机处于一个阴影锥中,使用Z-pass算法会有问题,这种情况下应该使用Z-fail算法)。
阴影锥不受封闭几何的影响。在下图中,

卫兵投射到地板上,投射的范围内有个封闭的箱子(此例中设定箱子不投射阴影)。根据现实世界的经验,箱子上会有卫兵投射的阴影,如图中所示。但光线经过箱子阻挡后应该不再前进,也就是说阴影锥经过箱子阻挡后不应该延伸了,于是箱子后面的地板上不应该再出现卫兵的阴影(真实世界中出现箱子的阴影,但是此例设定箱子不产生阴影)。图中的地板上出现了卫兵投射的阴影,这说明了阴影不会受到延伸方向上物体的影响。
在屏幕上看不到的物体也可以把阴影投影到可视的平截头体(view frustum)中。虽然看不到,但是这些物体
也必须得被渲染,渲染他们纯粹是为了得到产生阴影的相关数据。在不使用硬件加速的情况下,尽量避免物体离光源过近。
纹理阴影
纹理阴影算法的基本原理是:首先从光源的角度观察场景,把观察到结果渲染到一个纹理,纹理中只保存
深度值(深度缓冲中的值)。这样做的意义是,在纹理中保存了场景中的物体与光源之间的最短距离。然后从相机的角度进行正常渲染场景,计算每个像素与光源的距离,并与纹理对应的值进行比较,如果大于,那么说明它不是光线方向上离光源的最近的,会有阴影产生。/*可以有点疑惑,每个需要测试的像素如何与纹理中的像素一一对应呢?还是按照生成纹理图的原理,需要把测试顶点的位置坐标,转换到光源为视点的空间,也就是说从光源的角度,看看顶点应该在哪里。这样就可以一一对应比较了。当然这仅仅是为了比较的目的,真正渲染时顶点还是要先转换到视空间中(从相机角度看)*/。
纹理阴影速度上要比模板阴影算法快,但因为阴影被渲染到纹理中,而纹理具有确定的解析度,因此当阴影被扩展,拉伸时,效果会较差,如产生锯齿边等。
因为使用了纹理内存,因此它的尺寸决定了纹理阴影数的上限。ogre中可以管理一帧中可以使用的阴影纹理数:SceneManager::setShadowTextureCount()。每个光源都需要一个纹理。假如指定的纹理数少于光源数,ogre采用”先来先服务“的原则分配纹理。假如不能增加纹理尺寸来提高视觉效果,最好减小投射阴影的距离。阴影不会突然终结,ogre会淡化纹理阴影的边缘阻止有阴影与无阴影之间剧烈过渡。可以控制淡化半径。
Modulative阴影混合
正常场景渲染的颜色与阴影的颜色相乘来创建暗的、表示阴影的颜色。这种方法有从已经渲染的场景中”减去“光照影响的效果。阴影区域一律变暗,与进入阴影区的光线数无关。当有多个光源产生的阴影区
重叠时,阴影会非常暗,视觉效果很差。
Additive Shadow Masking
Modulative的方法是通过影响阴影区实现的。而Additive方法是只对处于光照中的区域有影响,对阴影区没
有影响。这样阴影区会受到别的光源的影响而变得稍亮,而相互重叠的阴影区也不会更暗。
ogre会把一个通道分为三个通道.
Ambietn,应用环境光到场景中,在这个通道没有纹理被渲染。
 Diffuse and specular, 这个通道对每个灯都渲染一次,当前灯产生的阴影区域不受影响。其余的区域与场景进行混合。同样也不使用任何贴花纹理。
Decal。纹理被应用到前面累积的颜色上。


 

你可能感兴趣的:(《Pro Ogre 3D Programming》读书笔记 之 第十一章 动态阴影)