节点树
首先我们来看一个场景构建的实例,并通过它来了解一下“状态节点”StateGraph 和“渲染叶”RenderLeaf 所构成的状态树,“渲染台”RenderStage 和“渲染元”RenderBin 所构成的渲染树,进一步了解这两棵树之间错综复杂的关系,以及理解它们与场景节点树之间更加复杂的关系。
上面是一个虚构的场景结构图,其中叶节点_geode3,以及所有六个几何对象均设置了关联的渲染状 态集(StateSet),且几何体 1 和几何体 2 共享了同一个 StateSet(ss11(0,-))。图中用“ss”加上数字代 号来标识这些 StateSet 对象,后面括号中的两个参数分别表示 setRenderBinDetails 的两个设 置项(“-”表示空字串,“R”表示“RenderBin”,“D”表示“DepthSortedBin”)。也就是
1
2
3
4
5
6
|
ss03->setRenderBinDetails( 0, “” ); ss11->setRenderBinDetails( 0, “” ); ss13->setRenderBinDetails( -1, “RenderBin” ); ss14->setRenderBinDetails( 1, “RenderBin” ); ss15->setRenderBinDetails( 10, “DepthSortedBin” ); ss16->setRenderBinDetails( 10, “DepthSortedBin” ); |
注意1、这个函数有两个传入参数,整型数表示渲染的顺序,以 0 为标准,小于 0 的渲染状态集(亦即包含了这个StateSet的StateGraph状态节点)将排列在前,大于0的则排列在后;字符串参数“RenderBin”或者“DepthSortedBin”作为名称时有特殊含义,其中“RenderBin”表示在渲染树中新建分支进行渲染,“DepthSortedBin”表示新建分支,并且所有要渲染的数据将按照深度值降序进行排序。
注意2、 “setRenderBinDetails(0, “”)”是缺省的设置,这里写出来是为了便于区别;我们还要知道 OSG 中所有的 Drawable 几何体对象都会自动关联一个 StateSet 对象,无论用户是否在自己 的程序中作了设置。 进入渲染后台之后,OSG 将为这个场景生成“状态树”。
状态树
它是由“状态节点”StateGraph 和“渲染叶”RenderLeaf 所组成的:
图中的“状态根节点”和“局部状态节点”都是由状态树自动生成的,其中“局部状态节点”的主要 工作是保存和维护一些渲染后台自动创建的渲染属性;而“全局状态节点”主要工作则保存了一个名 为_globalStateSet 的渲染状态集对象。它的取值是场景主摄像机的 StateSet,换句话说,任何对状态树的遍历都将首先及至 场景主摄像机的渲染状态,然后才是各个节点的渲染状态,这就是_globalStateSet 的功用所 在了。
而整个状态树的构建过程则可以参考上面的场景树结构图,其规则为:
1、状态树是根据渲染状态(StateSet)来生成的,那些没有设置 StateSet 的场景节点将 不会影响状态树的构架;
2、场景中的 Drawable 对象在状态树中被分别置入各自的渲染叶(RenderLeaf)中,而一个 或多个渲染叶必然被一个状态树末端的节点(StateGraph)所拥有;
3、共享同一个渲染状态的 Drawable 对象(图中的_drawable1 和_drawable2)在状态树 中将置入同一个末端节点。
生成状态树的同时,OSG 渲染后台还将生成对应的“渲染树”, 其组成为一个 RenderStage 对象和多个 RenderBind 对象。如果我们不使用 setRenderBinDetails 设置 StateSet 的渲染细节 的话,那么所有状态树中的末端节点(其中必然包含了一个或多个“渲染叶”)都会按遍历顺序保存到渲染树根节点(渲染台)中,渲染树的构建也就到此结束。
渲染树
但是,如果我们对于场景中部件的渲染顺序有特殊要求的话,那么渲染树也会因而变得 复杂,上面的场景示例后可能得到如下的一株“渲染树” :
根据渲染顺序的不同,渲染树生出了三个分支。相应的状态节点置入各个渲染元 (RenderBin)分枝中,其中渲染细节设置为“RenderBin”的状态节点(StateGraph)所处 的渲染元也可称为“不透明体渲染元”;而设置为“DepthSortedBin”的状态节点则将其附带 的渲染叶(RenderLeaf)送入“透明体渲染元”,于其中采用按深度值降序的方式排序绘制, 以获得正确的透明体渲染结果;未设置渲染细节的状态节点则直接由根节点(渲染台, RenderStage)负责维护。
一个渲染元中可以保存一个或多个状态节点(或渲染叶);一个状态节点(或渲染叶) 只能置入一个渲染元中。
上面的场景结构中,我们并没有设置 Geode 节点_geode3 的渲染细节。如果设置它也采 用“RenderBin”或者“DepthSortedBin”方式,按照指定的渲染顺序号来绘制,那么在渲染 树中_geode3 节点及其附带的几何体将构成更复杂的结构形式。例如: ss03->setRenderBinDetails( 1, “RenderBin” ); 其它均不变。此时虽然ss03和ss14的渲染细节设置完全一样,但是由于关联ss03和ss14 的节点之间是父子的关系,因此渲染树的结构将变为:
注意两个渲染状态(StateSet)的渲染顺序号相同时,它们不一定放入同一个“渲染元” 中,这还取决于两个 StateSet 对象在状态树中所处的层次。有关渲染细节设置的例子,可以 参考 osghangglide。
最后,我们分别用一句话来总结“状态树”与“渲染树”的这几个组成类。
osgUtil::StateGraph:状态树的分枝节点(状态节点),负责管理场景树中的一个渲染状 态(StateSet)对象,末端的 StateGraph 节点还负责维护一个 “渲染叶” (RenderLeaf)的列 表。
osgUtil::RenderLeaf:状态树的叶节点(渲染叶),负责管理和绘制场景树末端的一个几 何体(Drawable)对象。
osgUtil::RenderStage:渲染树的根节点(渲染台),负责管理默认渲染顺序的所有末端 StateGraph 节点(附带“渲染叶”),并保存了“前序渲染” (pre-render)和“后序渲染” (post-render) 的渲染台指针的列表。
osgUtil::RenderBin:渲染树的分枝节点(渲染元),负责管理自定义渲染顺序的末端 StateGraph 节点(附带“渲染叶”);渲染树的根节点和分枝节点多只能有“RenderBin” 和“DepthSortedBin”两类子节点,但可以根据不同的渲染顺序号衍生出多个子节点,它们 在渲染时将按照顺序号升序的次序执行绘制。