1. 渲染状态是控制3D图形渲染方式的一系列“开关”和“参数”的集合,它决定了GPU如何处理几何体的顶点和像素,最终呈现出什么样的视觉效果;渲染状态是“绘制规则”,不是几何体本身的属性,同一个几何体,用不同的渲染状态绘制,会呈现完全不同的视觉效果。
2. osg::StateSet:OSG的渲染状态管理器
① 继承自osg::Referenced,提供引用计数内存管理,共享同一个StateSet的节点不需要手动释放内存,避免内存泄漏。
② 核心作用:
(1)集中管理渲染状态:把所有渲染状态的渲染模式和渲染属性放在一个StateSet对象里,方便关联到场景树中的任意节点(Node)和可渲染对象(Drawable);
(2)自动状态优化:状态切换是GPU的性能瓶颈(每次切换都需要GPU停止当前工作,加载新状态),而OSG会跟踪当前的GPU状态,只有当新的StateSet与当前状态不同时,才会更新GPU状态,减少不必要的切换,最小化状态切换的开销;
【注:OSG在每帧渲染前,会对场景树中的所有节点的绘制顺序进行智能排序,目标是将渲染状态相同或相似的节点尽可能安排在一起连续绘制,从而将全局的状态切换开销降至最低。】
(3)状态共享(内存优化):多个节点可以共享同一个StateSet,减少内存占用;引用计数机制会自动管理共享的StateSet,当没有节点使用时,自动释放内存;
(4)子树状态隔离:不同的场景子树可以设置不同的StateSet,实现局部渲染状态的隔离。
③ OSG将渲染状态分为两部分:
(1)渲染模式:功能开关(是否开启某个功能),对应OpenGL的glEnable()和glDisable(),例如:是否打开灯;
(2)渲染属性:功能参数(开启功能后,这个功能的具体参数是什么),例如:灯的亮度、颜色。
④ 使用方式:从Node或Drawable获取或创建StateSet:node->getOrCreateStateSet();
3. 渲染属性和渲染模式
① 设置渲染属性:
(1)OSG为每个渲染属性都设置了对应的类,这些类都继承自虚基类osg::StateAttribute(无法直接实例化);
(2)使用步骤:
1. 从Node或Drawable获取或创建StateSet;
2. 实例化属性类并设置参数;
3. 通过setAttribute将属性对象绑定到StateSet。
② 设置渲染模式:
(1)模式的位掩蔽技术:
1. OSG用“位屏蔽”来管理这些开关:每个模式(如GL_CULL_FACE)对应一个唯一的位(比如第0位对应深度测试,第1位对应面剔除),所有模式的开关状态都被存储在一个整数(位掩码)中,OSG可以通过位运算快速比较和切换状态,大幅提升效率。
(2)使用步骤:
1. 从Node或Drawable获取或创建StateSet;
2. 用setMode设置开关:第一个参数是OpenGL的模式枚举,第二个参数是osg::StateAttribute::ON(开启)或osg::StateAttribute::OFF(关闭)。
③ 同时设置渲染属性和模式:
(1)原因:很多属性和模式是绑定关系,单独设置属性后,还需要手动开启对应的模式,否则属性不生效。OSG提供setAttributeAndModes函数,同时完成“属性关联”和“模式开启”,简化操作;
(2)使用步骤:
1. 实例化属性类;
2. 用setAttributeAndModes关联并开启模式,默认开启对应模式(第二个参数默认是ON,也可手动设置为OFF)。
4. 渲染状态的继承:
① 默认状态继承(父节点设置全局状态,子节点局部调整):
(1)默认继承:父节点的StateSet会自动传递给所有子节点,子节点如果没有自己的状态设置,就直接使用父节点的状态;
(2)子节点覆盖:如果子节点对同一个渲染状态设置了不同的参数,子节点的设置会覆盖父节点的对应项。
② 三种状态继承策略:
(1)osg::StateAttribute::OVERRIDE:父节点的该状态会强制所有子节点继承,子节点对该状态的任何修改都将失效【适用场景:需要全局强制某个状态时,无论子节点如何设置,必须遵循父节点的规则】;
(2)osg::StateAttribute::PROTECTED:子节点的该状态会被保护起来,父节点的对应状态无法覆盖它【适用场景:需要保护子节点的某个状态不被父节点污染】;
(3)osg::StateAttribute::INHERIT:子节点会完全放弃自己的状态设置,强制使用父节点的对应状态。
这些技术通过位屏蔽技术组合使用:
// 1. 获取根节点的StateSet(全局状态的入口)
osg::StateSet* state = root->getOrCreateStateSet();
// 2. 创建PolygonMode属性:正反面都用线框模式(LINE)
osg::PolygonMode* pm = new osg::PolygonMode(
osg::PolygonMode::FRONT_AND_BACK, // 应用于正面和背面
osg::PolygonMode::LINE // 渲染模式:线框
);
// 3. 关联属性并设置策略:开启模式(ON)+ 强制父节点覆盖(OVERRIDE)
state->setAttributeAndModes(pm, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
③ 状态继承的底层原理:
OSG在遍历场景树时,会维护一个状态堆栈,状态继承的规则正是通过这个堆栈实现的:
(1)进入子节点时:将父节点的状态压入堆栈,然后应用子节点的状态(根据继承规则决定是否覆盖);
(2)退出子节点时:弹出堆栈顶部的状态,恢复进入子节点前的父节点状态。
【注:持续优化中……】



