OSG報警特效學習總結


方法一:粒子系統

        OSG的粒子系統有自己定義好的模塊,如osgParticle::ExplosionEffect(爆炸模擬);osgParticle::SmokeEffect(煙霧模擬);osgParticle::FireEffect(火光模擬)。我覺得可以利用煙霧模擬和火光模擬來做報警特效的展示。

目的:

向場景中添加自定義的osgParticle實例,模擬坦克模型在地形上運動時產生的煙塵。

152001_ZFuJcourse17.1

-----------------------------

概述:

添加粒子效果可以有效提高仿真程序的外觀和真實性。粒子引擎一般用於模擬煙霧,火焰,塵埃以及其他一些類似的效果。如果要向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 -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;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM