标签:
方法一:粒子系统
向场景中添加自定义的osgParticle实例,模拟坦克模型在地形上运动时产生的烟尘。
-----------------------------
添加粒子效果可以有效提高仿真程序的外观和真实性。粒子引擎一般用于模拟烟雾,火焰,尘埃以及其他一些类似的效果。如果要向OSG场景中添加粒子效果,通常可以使用下面的一些类:
粒子系统(osgParticle::ParticleSystem)- 维护并管理一系列粒子的生成,更新,渲染和销毁。粒子系统类继承自Drawable类。粒子的渲染控制因此与其它Drawable对象的渲染类似:控制其渲染属性StateAttribute即可。OSG提供了一个方便的函数以允许用户控制三个常用的渲染状态属性。方法setDefaultAttributes可以用于指定材质(或者指定为NULL以禁用材质),允许/禁止附加的图像融合,允许/禁止光照。
粒子(osgParticle::Particle)- 粒子系统的基本单元。粒子类同时具有物理属性和图像属性。它的形状可以是任意的点(POINT),四边形(QUAD),四边形带(QUAD_TRIPSTRIP),六角形(HEXAGON)或者线(LINE)。每个粒子都有自己的生命周期。生命周期也就是每个粒子可以存活的秒数。(生命周期为负数的粒子可以存活无限长时间)所有的粒子都具有大小(SIZE),ALPHA值和颜色(COLOR)属性。每一组粒子都可以指定其最大和最小值。为了便于粒子生命周期的管理,粒子系统通过改变生命周期的最大和最小值来控制单个粒子的渲染。(根据已经消耗的时间,在最小和最大值之间进行线性插值)
程序员也可以自行指定最小到最大值的插值方法。(参见osgParticle::Interpolator的代码)
放置器(osgParticle::Placer)- 设置粒子的初始位置。用户可以使用预定义的放置器或者定义自己的放置器。已定义的放置器包括:点放置器PointPlacer(所有的粒子从同一点出生),扇面放置器SectorPlacer(所有的粒子从一个指定中心点,半径范围和角度范围的扇面出生),以及多段放置器MultiSegmentPlacer(用户指定一系列的点,粒子沿着这些点定义的线段出生)。
发射器(osgParticle::Shooter)- 指定粒子的初始速度。RadialShooter类允许用户指定一个速度范围(米/秒)以及弧度值表示的方向。方向由两个角度指定:theta角 - 与Z轴夹角,phi角 - 与XY平面夹角。
计数器(osgParticle::Counter)- 控制每一帧产生的粒子数。RandomRateCounter类允许用户指定每帧产生粒子的最大和最小数目。
标准放射极(osgParticle::ModularEmitter)- 一个标准放射极包括一个计数器,一个放置器和一个发射器。它为用户控制粒子系统中多个元素提供了一个标准机制。
粒子系统更新器(osgParticle::ParticleSystemUpdater)- 用于自动更新粒子。将其置于场景中时,它会在拣选遍历中调用所有“存活”粒子的更新方法。
标准编程器(osgParticle::ModularProgram)- 在单个粒子的生命周期中,用户可以使用ModularProgram实例控制粒子的位置。ModularProgram需要与Operator对象组合使用。
计算器(osgParticle::Operator)- 提供了控制粒子在其生命周期中的运动特性的方法。用户可以改变现有Operator类实例的参数,或者定义自己的Operator类。OSG提供的Operator类包括:AccelOperator(应用常加速度),AngularAccelOperator(应用常角加速度),FluidFrictionOperator(基于指定密度和粘性的流体运动进行计算),以及ForceOperator(应用常力)。
代码:
为了使用上面的类创建高度自定义化的粒子系统,我们可以遵循以下的步骤。(括号中的步骤是可选的,如果所建立的粒子系统比较基本,也可以忽略)
下面的代码将完成上述的步骤。首先,我们需要建立基本的坦克和地形模型。(稍后我们再添加坦克模型到场景中)
osg::Group* rootNode = new osg::Group(); osg::Node* terrainNode = new osg::Node(); osgViewer::Viewer viewer; terrainNode = osgDB::readNodeFile("//Models//JoeDirt//JoeDirt.flt"); if (! terrainNode){ std::cout << "Couldn‘t load models, quitting." << std::endl; return -1; } rootNode->addChild(terrainNode); osg::Node* tankNode = osgDB::readNodeFile("//Models//T72-Tank//T72-tank_des.flt"); if ( ! tankNode){ std::cout << "no tank" << std::endl; return -1; }
建立粒子系统的基本步骤是:创建一个粒子系统对象,一个更新器对象,以及一个粒子对象,同时设置场景。
// 创建并初始化粒子系统。 osgParticle::ParticleSystem *dustParticleSystem = new osgParticle::ParticleSystem; // 设置材质,是否放射粒子,以及是否使用光照。 dustParticleSystem->setDefaultAttributes(dust2.rgb", false, false); // 由于粒子系统类继承自Drawable类,因此我们可以将其作为Geode的子节点加入场景。 osg::Geode *geode = new osg::Geode; rootNode->addChild(geode); geode->addDrawable(dustParticleSystem); // 添加更新器,以实现每帧的粒子管理。 osgParticle::ParticleSystemUpdater *dustSystemUpdater = new osgParticle::ParticleSystemUpdater; // 将更新器与粒子系统对象关联。 dustSystemUpdater->addParticleSystem(dustParticleSystem); // 将更新器节点添加到场景中。 rootNode->addChild(dustSystemUpdater); // 创建粒子对象,设置其属性并交由粒子系统使用。 osgParticle::Particle smokeParticle; smokeParticle.setSizeRange(osgParticle::rangef(0.01,20.0)); // 单位:米 smokeParticle.setLifeTime(4); // 单位:秒 smokeParticle.setMass(0.01); // 单位:千克 // 设置为粒子系统的缺省粒子对象。 dustParticleSystem->setDefaultParticleTemplate(smokeParticle);
下面的代码将使用标准放射极对象来设置粒子的一些基本参数:例如每帧创建的粒子数,新生粒子的产生位置,以及新生粒子的速度。
// 创建标准放射极对象。(包括缺省的计数器,放置器和发射器) osgParticle::ModularEmitter *emitter = new osgParticle::ModularEmitter; // 将放射极对象与粒子系统关联。 emitter->setParticleSystem(dustParticleSystem); // 获取放射极中缺省计数器的句柄,调整每帧增加的新粒子数目。 osgParticle::RandomRateCounter *dustRate = static_cast<osgParticle::RandomRateCounter *>(emitter->getCounter()); dustRate->setRateRange(5, 10); // 每秒新生成5到10个新粒子。 // 自定义一个放置器,这里我们创建并初始化一个多段放置器。 osgParticle::MultiSegmentPlacer* lineSegment = new osgParticle::MultiSegmentPlacer(); // 向放置器添加顶点,也就是定义粒子产生时所处的线段位置。 // (如果将坦克和标准放射极定义与同一位置,那么我们可以实现一种 // 灰尘粒子从坦克模型后下方的延长线上产生的效果。) lineSegment->addVertex(0,0,-2); lineSegment->addVertex(0,-2,-2); lineSegment->addVertex(0,-16,0); // 为标准放射极设置放置器。 emitter->setPlacer(lineSegment); // 自定义一个发射器,这里我们创建并初始化一个RadialShooter弧度发射器。 osgParticle::RadialShooter* smokeShooter = new osgParticle::RadialShooter(); // 设置发射器的属性。 smokeShooter->setThetaRange(0.0, 3.14159/2); // 弧度值,与Z轴夹角。 smokeShooter->setInitialSpeedRange(50,100); // 单位:米/秒 // 为标准放射极设置发射器。 emitter->setShooter(smokeShooter); 现在我们将把放射极和坦克模型作为Transform变换节点的子节点添加到场景中。放射极和坦克均由变换节点决定其位置。刚才定义的放置器将会根据变换的参量安排粒子的位置。 osg::MatrixTransform * tankTransform = new osg::MatrixTransform(); tankTransform->setUpdateCallback( new orbit() ); // 回调函数,使节点环向运动。 // 把放射极和坦克模型添加为变换节点的子节点。 tankTransform->addChild(emitter); tankTransform->addChild(tankNode); rootNode->addChild(tankTransform); 下面的代码将创建一个标准编程器ModularProgram实例,用于控制粒子在生命周期中的更新情况。标准编程器对象使用Operator计算器来实现对粒子的控制。 // 创建标准编程器对象并与粒子系统相关联。 osgParticle::ModularProgram *moveDustInAir = new osgParticle::ModularProgram; moveDustInAir->setParticleSystem(dustParticleSystem); // 创建计算器对象,用于模拟重力的作用,调整其参数并添加给编程器对象。 osgParticle::AccelOperator *accelUp = new osgParticle::AccelOperator; accelUp->setToGravity(-1); // 设置重力加速度的放缩因子。 moveDustInAir->addOperator(accelUp); // 向编程器再添加一个计算器对象,用于计算空气阻力。 osgParticle::FluidFrictionOperator *airFriction = new osgParticle::FluidFrictionOperator; airFriction->setFluidToAir(); moveDustInAir->addOperator(airFriction); // 最后,将编程器添加到场景中。 rootNode->addChild(moveDustInAir); 下面的代码就是仿真循环的内容了。 viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.setSceneData(rootNode); viewer.realize(); while( !viewer.done() ){ viewer.frame(); } return 0;
标签:
原文地址:http://www.cnblogs.com/xiaocainiao2hao/p/5619935.html