主要的 Render State 分为 global state , lights 和 effects 。
一,抽象基类 GlobalState
该类为一个抽象基类,所有的全局状态类型如 alpha blending , triangle culling , material , polygon offset , stenciling , wireframe , depth buffering 等都要基于该类创建。 Node , Geometry 均有相关接口用于 global state 的存储,加载和移除。
这些派生类有两个共同点:( 1 )都要重载虚函数 GetStateType 。
( 2 )都要在 program initialization 时创建默认对象,在 program termination 时销毁对象。
二, Lights
Lights 的作用结果与 material 密切相关。
经过多次更改和权衡( p261-p263 ),作者最终决定将 Light 类写成一个通用类,其中包含了所有类型的光源所需的信息,并定义了枚举类 LightType ,以标识对象的光源模型。接口略。
三, effects 。详见 chapter3.4
四, RenderState 的更新。
当下列事件发生时, RenderState 需要更新:( 1 ) attach/detach global states ( 2 ) attach/detach lights ( 3 ) attach/detach effects (4) 场景图的拓扑结构改变。
RenderState 更新的顶层接口相对于 geometry state 要简单,只有一个 :UpdateRS()( 在 spatial 中)当上述情况发生时,调用 UpdateRS ()即可。注意,如果仅仅是 RenderState 的某个数据成员发生改变,则没有必要调用 UpdateRS ,因为场景图中每个节点存储的是 RenderState 的智能指针,而不是 RenderState 本身,因此,一旦 RenderState 的内容发生改变,所有共享该类的节点会马上感应到这一点,从而在 draw 的时候体现出来。
下面给出 UpdateRS 的函数调用图:
说明: N1 为 RenderState 更新的触发点。
N1 UpdateRS ()
声明 Gstack , Lstack
PropagateStateFromRoot parent--- à PropagateStateFromRoot(), 向上
PushState ,向上递归结束。
UpdateState
销毁 Gstack , Lstack (递归的终点)
若 N 不是触发点:
PushState
UpdateState 对每一个 chilid
N Child- à UpdateRS(), (向下递归开始。)
PopState (向下递归结束
(node)
UpdateState ( Geometry ) -- à 将栈中 RenderState 复制到本地。
向上递归的目的是在栈中加入触发节点之前所有父节点的 RenderState ,以便传给子节点。
向下递归的目的是将当前节点的所有 RenderState 传给子节点(本质是覆盖子节点的本地 RenderState )。
读者可能会有此种想法:不用当前节点的 RenderState 去覆盖 子节点的 RenderState ,而是通过修正,即当前节点中没有的不做任何动作,多出来的就添加进去,这样就可以免去覆盖,从而省略了 PropagateStateFromRoot 这一步。这是错误的 。例如,某子节点被一个新的子节点替换,这是如果没有 PropagateStateFromRoot (),就无法获得新子节点的全部 RenderState 。
当然了,添加 PropagateStateFromRootr ()的缺点是对于原有节点来说,这一步是多余的。
一点说明: Gstack , Lstack 并不仅是一个栈,而是栈数组,每种类型的 RenderState 拥有一个栈,这是因为可能出现多个同类型的 RenderState 连接到一个节点的情况。