在 WM4 中, culling pass 和 drawing pass 是分开的,负责该流程的三个核心类是 VisibleObject , VisibleSet , Culler 。下面一一详述。
一, VisibleObject
该类实际上是一个结构类,有两个 public 成员: Spatial* Object 和 Effect* GlobalEffect
前者用于存储单个的潜在可见的物体,后者用于存储与 Node 节点相关联的 global effect 。(在绘制中大有作为)。
二, VisibleSet 。
该类用于存储潜在可见物体的集合,并建立一个索引表用于绘制,详见 p197.
Public :
Void Insert ( Spatial* pkObject , Effect* pkGlobalEffect );
// 如果要插入的是 Geometry ,那么 Effect 指针设为空,如果要插入的是 Node ,并且关联了 global effect ,那么 effect 指针指向那个 Global Effect 。
带有 global effect 的 Node 类,是一种特殊信号,标记了 global effect 的起始点,而一旦该 Node 子节点的遍历结束,另一个符号被加入 VisibleSet ,用于标记 global effect 的终点。
三, Culler
该类用于( 1 )管理对场景图的剔除( 2 )管理对潜在 visible set 的存储。(如 insert )
Culler 类中维护了一个 VisibleSet ,用于存储剔除后得到的物体。
首先将指向整个场景的 Spatial 指针传给 Culler ,然后 Culler 类调用 Spatial 接口并将该 Culler 类传给接口,遍历过程由 Spatial 实现,但其中会用到 Culler 中的剔除函数。
Spatial 与 Culler 互相依赖,紧密结合。
Spatia :: OnGetVisibleSet() 调用 GetVisibleSet ,如果调用者是 Node , GetVisibleSet 中会继续调用 OnGetVisibleSet (对每一个节点),形成递归。
关于 PlaneState ,适用于标识该平面是否被激活,若检测到一个节点完全位于平面外,则节点下的每一个子节点均不需要检测,因此将 PlaneState 设为未激活,只需继承父节点的检测结果即可。
总结 :递归的结构基本分为两种( 1 )自身调用自身。
( 2 ) A 调用 B , B 调用 A , …….. 直到 A 返回。(有的 A 并不调用 B ,直接返回,通过多态性实现)。
递归函数体 分为三大块:( 1 )递归前的准备
( 2 )递归(循环调用)
( 3 )递归后准备。
( 1 )( 3 )可能没有,但( 2 )一定有,( 1 )和( 3 )往往相互呼应。
Culler 的核心函数是 IsVisible() ,待研究!!!
另外,在按空间关系结束 cull 后,可以再进行 RenderState 排序,然后 draw 。
另外,也可在 Cull 的过程中进行某种规则的排序(重载 GetVisible 即可)。
例如,以后要介绍的 Portal System 。