第六章 Spatial Sorting
Spatial Sorting 的两个目的:
(1) 便于不透明物体从前往后的绘制,半透明物体从后往前的绘制。
(2) 按 Render State 相似性排序,以减少 RenderState 改变的 次数。
一, BSP 树
该法用于粗略的空间排序。
BSP 类基于 Node 类,有 3 个子节点: positive,negative, 和 middle.
Positive 下的物体位于分割面的正侧, negative 同理, middle 下的物体横跨分割面。
二, Node —— Based Sorting 。
对 Node 下的子节点进行排序
三, Portal System
实质是一个有特殊剔除功能的场景图。
2 个任务:( 1 )通过出口 / 入口将所有的房间组织起来,用于遍历和排序。
通过边界入口更改视景体,进而用于剔除。
|
该结构是一个图,可能出现首尾相接的情况,因此应添加标记,注明某 ConvexRegion 是否已被遍历过,以防止死循环出现。
ConvexRegionManager 基于 BSP 类,它 的唯一作用是 确定视点在哪个 ConvexRegion 内,以确定遍历的起点。
ConvexRegionManager 可有可无,若游戏中未设置 BSP ,或者设置了其他类型的分割图,则完全可以用其他类代替 ConvexRegionManager ,此时 PortalSystem 仍可正常运作。
ConvexRegionManager 中含有遍历的入口:
ConvexRegionManager :: GetVisibleSet ( Culler& rkCuller , bool BnoCull )
{
(1) 确定视点所在的 ConvexRegion 。
(2) 如果得到一个 ConvexRegion ,调用 ConvexRegion->GetVisibleSet ( Culler , bnocull )
(3) 若没有得到,则视点在场景外,调用
Outside->GetVisibleSet
}
在这里,应注意一种特殊情况,即视景体的近裁减面与室内场景的边界墙相交,此时仿佛人物头部在墙体内,一只眼在室内,一只眼在室外,由于此时 ConvexRegionManager 已判定视点在室外,因此室内的物体不会绘制,屏幕上会出现一部分黑块,应尽量避免这种情况的发生。
ConvexRegion 类基于 Node 类,因此实际上它包含了一个节点,此节点代表整个房间内的所有物体,此外,该类还包含了与 Portal (出口,不是入口!!! )有关的接口以及链接。
另外,该类对 UpdaeWorldData ( double DaPPTIME )进行了重载,实际上添加了对 Portal 的 geometry state 的更新。(没有 Render State !!!! Portal 是抽象的入口,不被绘制 )因为 Portal 不是基于 Node 类,不会在 Node 的 geometry state 的更新中被自动更新,因此手动添加了这行代码。
ConvexRegion :: GetVisibleSet ( Culler& rkCuller , bool BnOCULL )
{
If (! m_bVisited )
{
M_bVisited=true ;
// 对每个入口所能看到的房间进行剔除
M_apKPortal[i]->GetVisibleSet(rkCuller,bNocull)// 注意其中包含了对入口本身的可见性检测。
// 调用基类中的 GetVisibleSet ,对房间本身进行剔除。
Node :: GetVisibleSet ( rkCuller , Bnocull );
M_bVisited=false ;
}
}
注意其中的 m_bVisited 是一个标识符,用于防止 Portal 图中死循环的出现。
Portal 类不是基于 Node 类,是 ConvexRegion 类的友元类。(有何作用?)
Portal 中含有 Portal 的几何顶点(模型,世界),以及作为出口(相对于包含该 Portal 的 ConvexRegion 而言)所连接的 ConvexRegion 。
ConvexRegion 在销毁时会利用内部的 Portal 指针直接销毁 Portal 数组,因为这些 Portal 不会被共享,而是专属于该 ConvexRegion 。
Portal 会根据几何顶点计算包围洞口的四边形(模型,世界)
在 UpdateWorldData 的过程中会通过模型计算出世界坐标。
Portal :: GetVisibleSet ( Culler& rkCuller , bool bnocull )
{
If (! m_bOpen ) {return : }// 如果门关着,什么也看不到。
If (! rkCuller.Isvisible(m_iVQuantity,m_akWorldVertex,true) ) {return;}
// 对 Protal 本身的可见性检测。
根据 Portal 修改 Culler 。
调用 ConvexRegion->GetVisibleSet
还原 Culler
}
四, user_defined maps 。有美工提供。
五, 遮挡剔除。
算法本身很复杂,用它提高游戏速度是困难的,可编写一些简单算法,如将某大型静态物体视为多边形,实时计算裁减视景体。
另外,随着图形硬件的发展,剔除算法写的简单点,可节省 CPU 时间。