方法一:粒子系统

        OSG的粒子系统有自己定义好的模块,如osgParticle::ExplosionEffect(爆炸模拟);osgParticle::SmokeEffect(烟雾模拟);osgParticle::FireEffect(火光模拟)。我觉得可以利用烟雾模拟和火光模拟来做报警特效的展示。

目的:

向场景中添加自定义的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(应用常力)。

代码:
为了使用上面的类创建高度自定义化的粒子系统,我们可以遵循以下的步骤。(括号中的步骤是可选的,如果所建立的粒子系统比较基本,也可以忽略)

  • 创建粒子系统实例并将其添加到场景。
  • (设置粒子系统的渲染状态属性。)
  • 创建粒子对象并将其关联到粒子系统。
  • (设置粒子的参数。)
  • 创建粒子系统更新器,将其关联到粒子系统实例,并添加到场景中。
  • (创建标准放射极,以定义:计数器 - 每帧创建的粒子数,放置器 - 粒子的出生位置,发射器 - 初始速度。)
  • (将标准放射极关联到粒子系统。)
  • (创建ModularProgram标准编程器实例,以控制粒子在生命周期中的运动:首先创建并定义Operator计算器;然后添加计算器到标准编程器。)

下面的代码将完成上述的步骤。首先,我们需要建立基本的坦克和地形模型。(稍后我们再添加坦克模型到场景中)

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 -;
}
rootNode->addChild(terrainNode); osg::Node* tankNode = osgDB::readNodeFile("//Models//T72-Tank//T72-tank_des.flt");
if ( ! tankNode){
  std::cout << "no tank" << std::endl;
  return -;
}

建立粒子系统的基本步骤是:创建一个粒子系统对象,一个更新器对象,以及一个粒子对象,同时设置场景。

// 创建并初始化粒子系统。
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(); // 单位:秒
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个新粒子。 // 自定义一个放置器,这里我们创建并初始化一个多段放置器。
osgParticle::MultiSegmentPlacer* lineSegment = new osgParticle::MultiSegmentPlacer(); // 向放置器添加顶点,也就是定义粒子产生时所处的线段位置。
// (如果将坦克和标准放射极定义与同一位置,那么我们可以实现一种
// 灰尘粒子从坦克模型后下方的延长线上产生的效果。)
lineSegment->addVertex(,,-);
lineSegment->addVertex(,-,-);
lineSegment->addVertex(,-,); // 为标准放射极设置放置器。
emitter->setPlacer(lineSegment); // 自定义一个发射器,这里我们创建并初始化一个RadialShooter弧度发射器。
osgParticle::RadialShooter* smokeShooter = new osgParticle::RadialShooter(); // 设置发射器的属性。
smokeShooter->setThetaRange(0.0, 3.14159/); // 弧度值,与Z轴夹角。
smokeShooter->setInitialSpeedRange(,); // 单位:米/秒 // 为标准放射极设置发射器。
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(-); // 设置重力加速度的放缩因子。
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 ;

OSG报警特效学习总结的更多相关文章

  1. osg for android学习之一:windows下编译(亲测通过)【转】

    1. 首先需要一个OSG for android的环境 (1)NDK 现在Eclipse 对NDK已经相当友好了,已经不需要另外cygwin的参与,具体可以参考 Android NDK开发篇(一):新 ...

  2. OSG描边特效osgFX::Outline的修改

    对一个三维场景中的物体实现描边特效,可以参考osg范例osgoutline 这个描边特效使用了模板缓存Stencil来实现,参见源代码osgFX/Outline.cpp 使用了两个Pass 第一个Pa ...

  3. QQ 5.0的一些特效学习 一

    虽然QQ5.0已经过去很久了,但是有些特效还是值得学习的 效果: 源码点我 导入的jar包, 一个是高版本的support.v4包,需要这个v4包中有ViewDragHelper. 我这里使用的是su ...

  4. Three.js 3D特效学习

    一.Three.js基本介绍 Three.js是JavaScript编写的WebGL第三方库.提供了非常多的3D显示功能.Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场 ...

  5. osg轮廓特效 【转】

    // -*-c++-*- /* * OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open s ...

  6. [原][osg][粒子特效]spark粒子特效生成流程

  7. QQ 特效学习 二 侧滑删除

    上篇文章: http://www.cnblogs.com/xurui1995/p/5798631.html 今天来写不仅是qq而且在别的软件上也特别流行的侧滑删除 其实套路和前篇的一样,一个自定义Vi ...

  8. WebGL——osg框架学习三

    今天继续来Draw绘制的osg模块的学习,昨天我们学习的是StateBin渲染状态树节点类,今天我们来继续学习下一个Draw的基础类DrawableEntity渲染对象实体类.这个类和Drawable ...

  9. osg for android (一) 简单几何物体的加载与显示

    1. 首先需要一个OSG for android的环境. (1).NDK 现在Eclipse 对NDK已经相当友好了,已经不需要另外cygwin的参与,具体可以参考 Android NDK开发篇(一) ...

随机推荐

  1. ExecutorService 的理解与使用

    ExecutorService 的理解与使用  http://my.oschina.net/bairrfhoinn/blog/177639 Java线程池ExecutorService http:// ...

  2. 矩阵乘法的MPI并行计算

    1.问题描述 矩阵乘法问题描述如下: 给定矩阵A和B,其中A是m*p大小矩阵,B是p*n大小的矩阵.求C = A*B. 求解这个问题最简单的算法是遍历A的行和B的列,求得C的相应元素,时间复杂度O(m ...

  3. oracle group by 使用

    SELECT supplier_id, max(evidence_date) AS evidence_date,max(TD_SUPPLIER_EVIDENCE_INFO_ID) AS TD_SUPP ...

  4. Oracle EBS-SQL (WIP-12):总装车间任务查询.sql

    select         WT.WIP_ENTITY_NAME                                                                任务名 ...

  5. 取PE文件的引入表和导出表

    直接上代码(这里列出C++和Delphi的代码),Delphi代码中包含导入及导出文件和函数列表,PE结构可参阅资料,很多很详细,需要注意的是,本例中是映射到内存,不是通过PE装载器装入的,所以对于节 ...

  6. Gradle DSL method not found: 'android()

    原文错误提示: Error:(16, 0) Gradle DSL method not found: 'android()'Possible causes:<ul><li>Th ...

  7. 关于Char* ,CString ,WCHAR*之间的转换问题

    GDI+所有类的接口函数如果要传递字符串作为参数的话,似乎都用UNICODE串,即WCHAR*.我开始也被整得晕头转向,因为窗口编程所用往往是CString,用IO流读文件数据又得到char *.得益 ...

  8. SWOT自我分析

    个人信息: 大三学生 二本大学 软件工程专业 一:SWOT自我分析 Strenghs(优势): 1.有着良好的作息习惯,坚持锻炼 2.专注力强,能沉下心来学习 3.有着强烈的危机意思,明白不仅则退的道 ...

  9. 人生第一场组队赛---2014.8 zju monthly

    暑期集训中段就组了队,不过一直没机会打比赛 昨天kitkat突然发现了zju要搞月赛,我想了一下题目对于我这种渣实在是有点难,于是想到干脆打一次组队赛吧,跟队友商量了一下也同意了 12点---17点  ...

  10. 利用协议代理实现导航控制器UINavigationController视图之间的正向传值和反向传值

    实验说明 (1)正向传值:比如A类里地值要传给B类用,就是我们先在A类中声明一个B类对象(当然B类头文件要import过来),然后把A类中得某个 值传递给B类中得某个值(所以需要在B类中先准备一个变量 ...