1 状态继承
当读者设置节点的渲染状态时,这个状态将被赋予当前的节点及其子节点。如果子节点对同一个渲染状态设置了不同的属性参数,那么新的子节点状态参数将会覆盖原有的。也就是说,默认情况下子节点可以改变自身的某个状态参数或者继承父节点的同一个状态。如图5—2所示的光照状态继承图体现了这个概念的实现过程。
状态继承特性在许多情况下都非常实用,但有时渲染可能需要更多特性。假设场景图形中有一个包含了实体多边形几何体的节点,如果要以线框模式来渲染场景图形,读者的程序就需要覆盖这种多边形渲染模式状态,而不论它出现在什么位置。OSG允许用户根据场景图形中任意位置的渲染属性和模式需求单独改变原有的状态继承特性。可以选择以下几种枚举形式。
- osg::StateAttribute::OVERRIDE:如果将一个渲染属性和模式设置为OVERRIDE,那么所有的 子节点都将继承这一属性或模式,子节点对它们的更改将会无效。
- osg::StateAttribute::PROTECTED:这种形式可以视为OVERRIDE的一个例外。凡是设置为 PROTECTED的渲染属性或模式,均不会受到父节点的影响。
- osg:StateAttribute:INHERIT:这种模式强制子节点继承父节点的渲染状态,其效果是子节点 的渲染状态被解除,而使用父节点的状态替代。
读者可以对这些参数进行位或叠加操作,然后再作为setAttribute()和setMode()建立一个场景图形和setAttributeAndModes()的第二个参数输入。下面的代码段将强制使用线框模式渲染场景图形:
//获取根节点的渲染状态 StateSet
osg:StateSel*state=root->getOrCreateStateSet();
//创建一个PolygonMode 渲染属性
osg:PolygonMode*pm=new osg:PolygonMode();
osg:PolygonMode::FRONT_AND_BACK,osg:PolygonMode::LINE);
//强制使用线框渲染 state->setAttributeAndModes(pm, osg::StateAmributeONjong::StateAtribute:OVERRIDE);
使用PROTECTED参量可以保证父节点的渲染状态不会覆盖子节点的渲染状态。例如,读者可能创建了一个发光的场景,其中包含有使用亮度照明的光源几何体,如果其父节点禁用了光照,那么光源几何体的渲染将会出错。这时,对光源几何体的GL_LIGHTING 渲染状态使用PROTECTED就可以保证它依然可用。
2 渲染状态示例
渲染状态(ClipeNode)示例的代码如程序清单所示。
#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/ClipNode>
#include <osg/PolygonMode>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/AnimationPath>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <iostream>
#include "utility.h"
osg::ref_ptr<osg::Node> createClipNode(osg::ref_ptr<osg::Node> subgraph)
{
osg::ref_ptr<osg::Group> root = new osg::Group();
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
// 多边形绘制模式,正面和反面都绘制
osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode();
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
// 启动多边形绘制模式,并指定状态继承属性为OVERRIDE
stateset->setAttributeAndModes(polymode, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
// 多边形绘制节点
osg::ref_ptr<osg::Group> wireframe_subgraph = new osg::Group;
// 设置渲染状态
wireframe_subgraph->setStateSet(stateset.get());
wireframe_subgraph->addChild(subgraph.get());
//root->addChild(wireframe_subgraph.get());
osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;
// 更新回调,实现动态裁剪
osg::ref_ptr<osg::NodeCallback> nc = new osg::AnimationPathCallback(subgraph->getBound().center(), osg::Vec3(0.0f, 0.0f, 1.0f), osg::inDegrees(45.0f));
transform->setUpdateCallback(nc.get());
//创建裁剪节点
osg::ref_ptr<osg::ClipNode> clipnode = new osg::ClipNode();
osg::BoundingSphere bs = subgraph->getBound();
bs.radius() *= 0.2f;
// 设置裁剪节点的包围盒
osg::BoundingBox bb;
bb.expandBy(bs);
// 根据前面指定的包围盒创建6个裁剪平面
clipnode->createClipBox(bb);
// 禁用拣选
clipnode->setCullingActive(false);
transform->addChild(clipnode.get());
root->addChild(transform.get());
root->addChild(wireframe_subgraph.get());
// 创建未被裁剪的节点
osg::ref_ptr<osg::Group> clippedNode = new osg::Group;
clippedNode->setStateSet(clipnode->getStateSet());
clippedNode->addChild(subgraph.get());
root->addChild(clippedNode.get());
return root.get();
}
int main()
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Node> root = new osg::Node();
// 加载模型
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(GetCurrentPath() + "\\Data\\cow.osg");
root = createClipNode(node.get());
// 优化场景数据
osgUtil::Optimizer optimzer;
optimzer.optimize(root.get());
setWindowSize(viewer.get(), 600, 400, "ClipNode");
viewer->setSceneData(root.get());
viewer->realize();
viewer->run();
return 0;
}
效果图
动态效果图