http://blog.csdn.net/cainiao_liu/article/details/5235977
最简单的流水线可见性处理如下:
对每个物体转换到世界坐标,然后进行视椎体剔除,其次是背面消隐,最总通过空间剪裁和光栅化期间的图像空间裁剪得到最终的要绘制的图像。
在场景很简单,物体很少的情况,上述方法是可行的。但考虑到现代游戏的场景复杂程度,如果还采用上面的流水线来提出多边形,就显得力不从心了,因为这意味着在每次移动摄像机的时候都要对场景中的所有的物体进行视椎体的剔除及背面消隐,而这根本是不肯能的。
因此,就迫切一种方法,能快速的对大部分场景进行剔除操作。进一步说就是,能根据当前视点位置快速得到当前可见的多边形集合。
而这就需要对空间进行有效的划分,即对物体要有一个有效的管理。
常见空间划分算法有:
BSP、BHV、OCTREE等
常见的可见性算法有:
PVS、OC、portal等
下面先对最重要的BSP算法进行简单的分析:
BSP树的原理:使用分割面将空间划分成凸形子空间构成的二叉树。
BSP树的应用:
<1>大规模剔除物体。
<2>碰撞检测。
<3>可以根据视点的位置很快的确定当前正确的渲染顺序(从后到前或从前到后)。(注:现在的游戏99%都不采用该方法进行渲染)
根据BSP树的原理,很容易联想到,如果把多边形自身作为分割面,则有可能在拥有很多房间或关卡的室内场景游戏中发挥作用。
具体来说就是以多边形链表作为输入提供给空间划分系统来创建BSP树。
步骤:
<1>选择第一个多边形作为分割面。如果链表中只剩一个多边形或没有多边形则算法结束;
<2>判断下一个多边形在分割面的前面还是后面,分别添加到front和back链表中;
<3>递归处理front和back链表;
显示和访问BSP以根据当前视点获得正确的绘制顺序由于应用不多,在此就不在详细介绍了。
创建BSP树对时间是不敏感的,因为将通过某种建模工具生成模型及对应的BSP数并保存到磁盘中,即创建树的过程是离线的。
(留个问题以后详述:什么工具可以生成BSP,怎么生成,以什么格式保存,在使用时又是如何加载?)
BSP树的局限性:只适合半静态场景,如果多边形在本超平面内平移,BSP树是不会改变的,但是如果旋转多边形则需要重新生产BSP树。
下面讨论一下BSP在剔除上的应用:
凸形子空间特性和便利的线性时间复杂度使BSP树非常适合于大规模剔除操作。
下次主要讨论:
<1>背面消隐
<2>视景体剔除
先来复习一下背面消隐:
前提为左手坐标系,每个三角形都会以一定顺序存储三个顶点,按照这个顺序观察三角形,如果是顺时针方向则该面为三角形的正面,另一个面为三角形的背面。有了该假设,我们就可以计算三角形的面法线了,该法线垂直三角形面并指向三角形的正面。选择三角形面上的一点为起点,视点为终点构造一个向量,起名叫做视点向量。根据法线向量和视向量的点积的符号很容易计算该面是否是正面朝向的,即是否可以被消隐。如果启动了背面消隐则三角形只有一面是可见的,如果要求三角形两面都可见则应该禁用背面消隐。
禁用背面消隐:g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
通过背面消隐可以消除一部分三角形,但是普通的背面消隐存在局限性:
<1>由于它没有考虑观察向量方向,所以可能会产生误差。比如,通过普通背面消隐判断为可见的三角形,由于观察方向向量会导致三角形实际是不可见的。
<2>在室内环境中有很多面都是双面可见的,这时普通的背面消隐就失去了存在的意义。
所以必须把观察向量考虑进来,产生一种新的更严格的背面消隐算法,具体算法就不在赘述了。
有了上述的背面消隐算法,结合BSP树会在视景体剔除中发挥极大作用。因为如果根据背面消隐算法知道当前分割面相对视点是否可见,如果不可见,并且视点在分割面的背面则可以判断出,在该分割面前面的所有的面都是不可见的。同理,如果视点在分割面的前面,且该分割面是不可见的,则可判断在该分割面后面的所有的面都是不可见的。这样就可以迅速的剔除视椎体以外的大量三角形。
到此为止,简单的介绍了使用BSP树对视椎体进行剔除的算法。但是,到目前为止,插入到渲染列表中的的三角形在实际情形中还是有很多是不可见的,也就是冗余的。为了剔除这些冗余三角形,就出现了PVS算法。
PVS(潜在可见集),可以手动建立,也可以使用工具建立,可以存储成数组,也可以存储成矩阵,也存在很多编码方式,在此不再赘述。总之是离线创建的。在插入到渲染列表之前在使用PVS来提取冗余三角形。
Portal(入口),是一种实时的PVS,它根据Portal的大小对视椎体进行裁剪,根据新的视椎体来确定PVS。具体怎么实现以后再介绍。
明天再介绍,BHV和8叉树。
前面讨论的BSP和Portal大多数情况会被用于室内场景的管理,更确切的说是在充满分割面的场景中。在室外场景管理中一般会用到BHV(包围体层次结构)或八叉树(num_division = 2的一种特殊的BHV)。
关于如何创建BHV及如何遍历BHV树利用视椎体进行剔除就不在赘述了。但需要认识到以下几点:
<1>BHV树也是需要离线创建的。
<2>层数的限制很自由,至少有以下选择:
(1)在节点的大小达到特定值时;
(2)在达到特定层数时;
(3)在每个节点包含的多边形的数目达到特定值时;
<3>8叉树比较常用,是因为它能很好的模拟3D坐标系有8个象限组成的特性。
最后,让我们来探讨一下OC(遮掩剔除):
在实际应用中,有时候不想使用有关可见性的静态解决方案,因为游戏世界可能频繁变换,PVS、BSP、BHV都不适合。
可喜的是,我们发现在游戏中经常会有一些很大的物体,它们会遮掩大部分场景,这就为OC提供了可能性。
OC技术的步骤如下:
<1>遍历完全位于视椎体内的且可见的所有的物体,选择n个最近、最大的物体。
<2>将物体投影到屏幕空间,并计算投影区域的面积。从中选择m个投影面积较大的物体,然后计算每个遮掩物的内接矩形。
<3>将遮掩矩形加入到遮掩体中,然后根据遮掩体对所有多边形和物体进行检测,剔除所有被遮掩的物体。
下面是使用OC需要注意的几点:
<1>可以离线选择一部分遮掩物,在运行阶段根据潜在的遮掩物进行选择,速度会很快。
<2>一般结合BSP、Portal、8叉树等场景管理,才能使效率很高。
到此为止,关于空间划分和可见性算法基本介绍完毕。后面会结合具体引擎,关于该专题进行深入分析,并对以前留下的问题进行阐述。