admin 管理员组文章数量: 1086019
2024年3月12日发(作者:canvas同济)
……
GRAPHICS AND IMAGE PROCESSING…一……… ……………一………………………………………… …… …
OsG的粒子特效仿真
侯学隆宋伟健
摘 要:OSG是一款市场占有率非常高的3D图形开发库,粒子特效的开发的一直是其难点。在
介绍粒子系统的基础上,分析了OSG中的粒子对象类的功能与继承关系,提炼粒子特效仿真的思
路,并给出一个粒子特效实例。
关键词:粒子系统:特殊仿真:OSG
雨、雾、云、爆炸、火焰、烟尘、燃烧等战场特效是增强 4)根据粒子属性变化的动态特性改变其属性值。
虚拟环境逼真度的有效手段,在三维游戏、战场环境仿真中具
5)删除系统中已死亡的粒子。
有重要作用。OSG是一款高性能的3D图形开发库,在游戏、 6)绘制所有剩余的粒子。
视景仿真、可视化仿真、虚拟现实等领域具有很高的市场占有 步骤3)、4)、5)、6)反复循环就形成了物体的动态变化
率。OSG基于粒子系统思想提供了一整套完整的C++类库对特
过程。
效进行抽象、建模与仿真.如何有效利用这些类构建特定的战
场特效是广大OSG开发者非常关注的问题,也是一个难点问
2 OSG粒子特效相关类
题。在此主要介绍OSG粒子类及特效仿真方法,并给出一个 OSG提供了一系列类对粒子系统进行封装,域名空间为
具体的仿真实例。 osgParticle,程序员使用这些类可以设计各种粒子特效。主要
1 粒子系统
的相关类包括:
2.1 osgParticle::ModularEmitter
对于诸如雨、雪、云、火焰、烟雾、爆炸等这些特殊视景 标准放射器(osgParticle::ModularEmitter)用于管理计数
效果的实时模拟一直是计算机图形学研究的难点,而粒子系统
器、放置器、发射器和粒子群,它为用户控制粒子系统中多个
是解决这一难点的有效方法。
元素提供了一个标准机制,如图1所示。
粒子系统的基本思想是:用粒子群来描述不规则物体的属
性及其变化,每个粒子均具有形状、大小、颜色、透明度、运
Os Re龟 8nc d
动速度、运动方向、生命周期等属性。这些粒子不是一个静态
fl
的整体,而是随着时间的推移处在不断运动中的粒子集合体。
其中粒子群的分布结构可以改变,各个粒子的位置可以移动,
新的粒子可以不断产生,同时旧的粒子不断死亡
l。sg:N。de l
同其他描述不规则物体的方法相比,粒子系统具有以下3
个特点:
{
osgParIicle::PatlicleProcessor
(1)对物体的描述不是通过原始的具有边界的面元(如多边
形集合)来描述,而是通过一组定义在空问的原始粒子来描述。
(2)粒子系统不是一个静态实体,每个粒子的属性均是时
}霸嘲酶锈每遵蚓
间的函数。
(3)由粒子系统描述的物体不是预先定义好的.其形状位
Osgpa糠}0 0幽lar嚣m瞅 f
置等属性均用随机过程来描述。
通常用粒子系统绘制一幅画面需要如下步骤:
图1 放射器类继承/派生关系
1)分析物体的静态特性,定义粒子的初始属性。
2.2 osgParticle::ParticleSystem
2)分析物体的运动规律,建立粒子属性变化的动态特性。
粒子群(osgPanicle::PamcleSystem)是OSG粒子系统的核
3)在系统中生成具有一定初始属性的新粒子。 心,它维护并管理一系列粒子的创建、更新、渲染和销毁。粒
垴壤趣2姣。巧lo等.1豢1护
…… … ‘ ‘ … …‘ … … 一
实用第一 智慧密集
∞ 目 目 !∞ & s i ∞ ! ∞ E 日 ± ! i 自
子系统类继承自Drawable类,控制粒子的渲染,因此与其他
Drawable对象的渲染类似,控制其渲染属性stateAttribute即
可。OSG提供了一个方便的函数setDerauhAttrihutes以允许用
户控制粒子使用的纹理、允许/禁止发光、允许/禁止光照3个
属性。派生类ConnectedParticleSystem用于导弹、飞机等轨迹
特效,单个粒子被渲染成带状(ribbon),如图2所示。
图2粒子群类的继承/派生关系
2.3 OsgPar“cIe::ParticIe
粒子(osgParticle::
r
Particle)是粒子系统的基本单元,它被
放射器创建后加入到粒子群中。粒子具有物理属性和图像属
性,它的形状可以是任意的点(POINT)、四边形(QUAD)、
四边形带(QUAD_TRIPSTRIP)、六角形(HEXAGON)或者线
(LINE)。每个粒子都有自己的生命周期,即每个粒子可以存活
的时间(秒)。生命周期为负数的粒子可以存活无限长时间。
粒子系统通过改变生命周期的最大和最小值来控制单个粒子的
渲染。所有的粒子都具有大小
雾
(SIZE)、ALPHA值和颜色
(COLOR)属性,这些属性均可以指定一个范围,即最大和最
小值。粒子属性会根据已经消耗的时间,在最小和最大值之间
进行线性插值(用户也可自定义插值方式)。
2.4 OsaParticIe::Placer
放置器(osgParticle::Placer)将粒子作为输入,用于设置
粒子的位置。它作为ModularEmitter的一部分,用户可以使用
预定义的放置器或者定义自己的放置器。预定义的放置器包
括:点放置器PointP1aceT(所有的粒子从同一点出生)、长方
体放置器BoxP1acer(所有的粒子从一个长方体内产生)、扇面
放置器sectorP1acer(所有的粒子从一个指定中心点,半径范围
和角度范围的扇面出生)、线段放置器SegmentPlacer(所有的
粒子从一条线段上产生),以及多段放置器MultiSegmentPhacer
(用户指定一系列的点,粒子沿着这些点定义的线段出生),如
图3所示
与矗
图3放置器类的继承/派生关系
2.5 OsgPa nicIe::ShOOter
发射器(osgParticle::Shooter)在内部被ModularEmitter所
用,是一个用于指定粒子的初始速度范围的抽象类。派生类
RadialShooter类允许用户指定一个速度范围(米/秒)以及弧度
值表示的方向。方向由两个角度指定:theta角——速度矢量
与z轴的夹角,phi角——x轴与速度矢量投影到XY平面所得
矢量的夹角,如图4所示
图4发射器类的继承/派生关系
2.6 osgParticle::Counter
计数器(osgParticle::Counter):控制每一帧产生的粒子数。
ConstantRateCounter用于指定每秒或每帧最少产生的粒子数:
RandomRateCounter类允许用户指定每帧产生粒子的最大和最
小数目,如图5所示。
图5计数器类的继承/派生关系
2.7 osgParticle::ParticleSystemUpdater
粒子群更新器(osgParticle:ParticleSystemUpdater):用于
自动更新粒子。将其置于场景中时,它会在拣选遍历中调用所
有“存活”粒子的更新方法,如图6所示。
……
GRAPHICS AND l啊^GE PROCESSING………………………….、-………… ……一 …… …,… ……… ………
图6粒子群更新器类的继承/派生关系
2.8 osgParticle::ModularProgram
标准编程器(osgParticle::ModularProgram)在单个粒子的生
命周期中,用户可以使用ModularProgram实例控制粒子的位置,
ModularProgram需要与Operator对象组合使用,如图7所示。
图7标准编程器的继承/派生关系
2.9 osgParticle::Operator
操作器(osgPanicle::0perator)提供了控制粒子在其生命
周期中的运动特性的方法。用户可以改变现有Operator类实例
的参数,或者定义自己的Operator类。OSG提供的Operator类
包括:AccelOperator(加速度)、AngularAccelOperator(角加速
度)、FluidFrictionOperator(空气阻力或者流体操作)以及
ForceOperator(压力),如图8所示。
图8操作器类的继承/派生关系
在OSG中除了以上粒子系统C++类,还包含有预定义的
特效类:
(1)osgParticle::ExplosionDebrisEffect(爆炸碎片);
(2)osgParticle::ExplosionEffect(爆炸);
(3)osgParticle::SmokeEffect(烟);
(4)osgParticle::SmokeTrailEffect(尾焰轨迹);
(5)osgParticle::FireEffect(火焰);
(6)sgParticle::PrecipitationEffect(雨、雪)。
3 开发方法
在OSG中,采用粒子系统模拟特殊效果有两种方法:一
是采用OSG中已经定义好的粒子系统模块;二是根据需要,
自定义粒子系统。 .
(1)预定义粒子系统的使用
11创建预定义粒子系统模块对象,设置相应的参数。
21作为子节点加到到场景节点中。从粒子系统的的关系
继承图中.可以知道它们继承自osg::Node或者osg::Group节
点,因此可以直接作为一个节点加入到场景中。
(2)自定义粒子系统的方法与步骤
1)创建粒子群(osgPartlcle::ParticleSystem),并将其加入
到场景中。设置相应的属性,如材质、放射及光照。
2)创建粒子(osgParticle::Particle),控制场景中每一个粒
子的特性并关联到粒子群。设置粒子对应的特性,如大小、颜
色、生命周期及重量等。
3)创建粒子系统放射器(osgParticle::ModularEmitter),标
准的放射器包括3个组成部分计数器(Counter)、放置器
(Placer)、发射器(Shooter),设置相应的属性,如位置、形
状、速度和方向等。
4)创建粒子系统编程器对象(osgParticle::Program),控制粒
子在声明周期内的运动。一个标准编程器对象包含各种操作器,
如osgParticle::AccelOperator,osgParticle::FluidFrictionoperator等。
5)创建粒子系统更新器(osgParticle::ParticleSystemUp—
dater),用于管理每帧的粒子的属性,如位置、速度、方向等。
通过上面的步骤,可以完成一般粒子特殊效果的仿真.用
户也可根据需要调整各对象实例的创建顺序。各粒子特效对象
的调用关系如图9所示。
r fr :】tI Elf.】 .… l‘ ’H {c 0I1『l 1
【 。 h¨_ I,
Ll lJ № ;, ・J
j 1
J¨ l【mt0】
十
l
¨ {…”一- -一 -{
j 拍J ’ }1lJ0 jd i” n I
|¨ j jj J
d
。. 、
_ 1。s—m - -” 一
f1K rll【 ・j P 】-j】 、 r”口 ad l'、Ⅱ ,¨l ¨ H ( 】
图9粒子特效对象相互调用关系
 ̄
2010 .
11
墨捆硝 仪
”
聚
.
∥
… … ’吣 *…H …H … ‘,一……1
~ … …
实用第一 智慧密集
4开发实例
基于Visual Studio 8.0和OSG2.8,利用粒子特效类编程实
现了固定翼飞机螺旋桨引擎着火、冒烟效果。
秘龟犍火球
void createFire8aII(osg::MatrixTransform smokeNode)
{
//创建粒子对象,设置其属性并交由粒子系统使用。
osgParticle::ParticIe particleTempalte;
lpatticIeTempalte.setShape(OsgParticle::Particle::QUAD)
particleTemlpaIte.setLifeTlme(1.5) //单位:秒
{particteTempaIte.setSizeRange(osgParticte::rangef(3.0f,
.
Of))=//单位:米
particleTempalte.setAIphaRange(osgParticle::rangef( O)):
。≯JparticleTempatte.setColorRange(osgParticle::rangev4(
osg::Vec4(1.Of, 2f,0.Of,1.of),//0。"…0 3f,0.4f, .Of
osg::Vec4(0.1f,0.1f,O.1f,0)//0.95f,0.75f,0,1(1J1, 1)
))
particleTempalte.setPos tion(os g=:Vec3(0.0f,0.0f,0 Of))
Ip;articleTempalte.setVelocity(osg::Vec3(0.0f,0. O.Of)):
pa ele_l.=empalte.setMass(o.1 //单位:-T- ̄
。
∞rticleTempalte.setRadius(0.2f);
particleTempalte.setSizeInterpolator{new osgPartic}e L_
Linea Interpolator);
particleTempaIte,setAIphalnterpolater(new osgParticle::
Linearlnterpotator):
¨lparticleTempalte.setCoIo rInterpolator(new osgPaI.-七icIe::
Linearlnterpolator]l:
- //仓U建并初始化粒子系统。
osgParticte::Pa cIeSystem *particteSystem=new
osgParticte::ParticleSystem
0I ̄articleSystem->setDataVariance(osg::Node::STATIC);
//设置材质,是否放射粒子,以及是否使用光照。
pparticleSystem->setDefauItAttributes( smoke.叼b",true,
false);
osg::Geode geode new osg::Geode;
geode->addDrawable《particleSystem);
smokeNode->addChiId(geode
■ll臌置为粒子系统的缺省粒子对象o
particleSystem 一>setDefaultParticIeTemplate(parti-
cleTemp ̄lIte);
一。 删莛取放射极中缺省计数器的旬柄,调整每帧增加的新粒
《 数目
osgParticle::RandomRateCounte *partic}eGenerateRate
=new OSgParticle::RandomRateCounter0
p鑫rtieIeGenerateRate一>setRateRange(30,50);
,,每秒新生成的粒子范围
particIeGenerateRate一>setDataVariance(osg::Node::DY-
NAMIC); 一
//自定义一个放置器,这里创建并初始化--4"A放置器
osgParticle::PointPlacer partictePlace ;new osg-
与
麓
Particle::PointPlacer:
particlePlacer一>setCenter《0sg::Vec3(0.Of,O.0fJ0.0f));
particlePIacer一>setDataVariance(osg::Node::DYNAMIC);
,/自定义一个弧度发射器
OsgParticle::RadiaIShooter particleShooter=new osg-
Particle::RadialShooter;
∥设置发射器的属性
particleShooter一>setDataVa ance《Osg::NOde::DYNAM
IC
particleShooter->setThetaRange(一0.785398f.0.785398f);
//弧度值,与Z轴夹角
particIeShooter一>setPhiRange(一0.785398f,0.785398f)
pafticleShooter一>set1nitialSpeedRange(5,7.5f);//- ̄位:米/秒
//仓峰E标准放射极对象
osgParticle::ModularEmitter*emitter=new osgPaft
cle::ModularEmitter;
emitter->setDataVariance(osg::Node::DYNAMIC);
emitter一>setCullingActive(false);
/将放射极对象与粒子系统关联。
emitter">setParticleSystem(particleSystem);
//设置计数器
em ter一>setCOunter(parEicleGenerateRate):
//设置放置器
emitter->setPtacer(particleP!acer);
,,设置发射器
emitter->setShooter articleShooter);
//把放射极添加为变换节点
smokeNode一>addChild(emitter);
//添加更新器,以实现每帧的粒子管理。
OsgPar【icIe::PanicleSystemUpdater particleSys-
temUpdater=new osgParticle::Pa icIeSystemUpdater;
//将更新器与粒子系统对象关联。
particleSystemUpdater,>addParticleSystem(parti,
cleSystem):
//将更新器节点添加到场景中。
smokeNode一>addChild(particleSystemUpdater);
//创建标准编程器对象并与粒子系统相关联。
OsgParticle::ModularProgram particleMoveProgram=
new osgParticie::ModularProgram;
particleMoveProgram,>setParticleSystem《particieSys,
tern); ’
//最后,将编程器添加到场景中。
smokeNode一>addC d(particfeMOvePr0gram)
)
//e ̄J建浓烟
void createDarkSmoke(osg::MatrixTransform smokeNode)
(
,/创建粒子对象,设置其属性并交由粒子系统使用。
osgParticle::Particle particleTempalte;
particIe。rempalte.setShape(osgParticle::Particle::QUAD);
particleTempatte.setLifeTime(1 O)://单位:秒
particleTempaIre.setSizeRange(osgParticle::rangef(11.0f,
…
GRAPHICS AND IMAGE PROCESSING .…x -
(osgParticte::rangef
… 一…… … … …~ ;… …㈣ … …一‘H … …
1 2.Of)):N单位:米particleS hooter->setln alSpeedRange(1 0,1 5):
particleTempatte.setAIphaRange ∥单位:米
(1,O)):
particleTempalte setColorRange(osgParticle::rangev4(
osg::Vec4(O.Of,0.Of,0.Of,0_5f),N(O.1f10.1f,O. O.5f)
osg::Vec4(O 5f,0.5f,0.5f,1.5f)N0.95f,0.75f,0,1
)):
particleTempalte.setPosition(0sg::Vec3(0.Of,0.Of,0.O吡
particleTempalte.setVelocity(osg::Vec3(O.Of 0。Of,O.Of)):
particteTempalte.setMass(O.1 f):∥单位:千克
particleTempalte.setRadius(O.2f):
particleTempalte.setSizeInterpolator(new osgParticle::
LinearlnterDolatOr):
particleTempalte.setAIphalnterpotator(new osgParticle::
LinearInterpOlat0r):
particleTempalte.setColorInterpofator(new osgPatticle::
LinearInterpOIat0 r):
∥创建并初始化粒子系统。
osgParticle::ParticleSystem particteSystem=new
osgParticle::ParticleSystem;
particleSystem一>setDataVariance(osg::Node::S IC):
∥设置材质,是否放射粒子,以及是否使用光照。
particleSystem一>setDefaultAttributes(”smoke。rgb’',false.
false);
osg::Geode geode=new osg::Geode;
geode一>addDrawable(particleSystem):
smokeNode一>addChlld(geOde)
//设置为粒子系统的缺省粒子对象。
particleSystem 一>setDefaultParticleTemplate (parti-
cleTempalte);
∥获取放射极中缺省计数器的旬柄,调整每帧增加的新粒
//子数目
osgParticle::RandomRateCounter particleGenerateRate
=new osgParticle::RandomRateCounterO;
particleGenerateRate一>setRateRange(30,50):
//每秒新生成的粒子范围
DarticIeGenerateRate一>setDataVariance(osg::Node::DY.
NAMlC):
∥自定义一个放置器,这里我们创建并初始化一个点放置器
osgParticle::PointPlacer particlePlacer new osg
Pa rticle::PointPlacer:
particlePlacer一>setCenter(osg::Vec3(O.Of,O.0f;0;0Bf))
particlePlacer一>setDataVariance(osg::Node::DYNAMlC:C)
//自定义一个弧度发射器
osgParticle::RadialShooter particleShooter 2 new osg-
Pa cle::Rad_alShooter;
∥设置发射器的属性
particleShooter一>setDataVariance(osg::Node::DYNAM。
lC):
particleShooter->setThetaRange(-O.1 f,O.1 f)=
∥弧度值,与Z轴夹角0.392699f
pa rclcleShooter一>setPhiRange(一O.1f,O;1f):
//创建标准放射极对象
osgParticle::ModularEmitter emitter=new osgPatti_
cle::ModularEmitter;
emitter一>setDataVariance(Osg::NOde::DYNAMlC):
emitter->setCullingActive(false);
∥将放射极对象与粒子系统关联。
emitter->setParticleSystem(particteSystem);
∥设置计数器
emitter一>setCOunter(particIeGenerateRate);
//设置放置器
emitter->setPlacer(particlePlacer);
∥设置发射器
emitter->setShooter(particleShooter}:
//把放射极添加为变换节点
smokeNode->addChild(emitter);
//添加更新器,以实现每帧f约粒子管理。
osgParticle::ParticleSystemUpdater particleSys-
temUpdater=new 0sgParticle::ParticleSystemUpdater;
∥将更新器与粒子系统对象关联。
plarticleSystemUpdater ->addParticleSystem(parti-
cleSystem);
,/将更新器节点添加到场景中。
smokeNode->addChild(particleSystemUpdater);
osgPatticle::ModularProgram particleMoveProgram
neW osgParticle::ModularProgf-am:
particteMoveProgram->setParticleSystem(partiCleSys-
tem):
//最后,将编程器添Dull场景中。
smokeNode->addChild(particleMoveProgram);
}
t jma.nIint argc,』CHAR*argv[])
{
//根节点
osg::Group*rootNode=new osg::Group
osgViewer::Viewer viewer;
//毒戋入飞机模型
osgl::Node*flightNode=osgDB::readNodeFile( cessna.
OSg'1)=
.f(!flightNode)
{
std::cout<《“no flight”<<std::endl;
return-1 I l
}
//飞机变换节点
osg::MatrixTransform flightTransform=neW osg::Ma
trixTransform()=
flightTransform一>addChild(flightNode);
r0otNode->addChild(flightTransform);
∥引擎烟雾
osg::Matr1XTransform firebaIlAndSmoke=new osg::
蒜 69
#一
#
t I’ … 一 。H … … l 、 ………一 …
实用第一/智慧密集
MatrixTransform0;
//仿真循环
viewer.run()
return O:
createFireBal rebaI1AndSmoke);
createDarkSmoke(fireballAndSmoke);
fireballAndSmoke->setMatrix(osg::Matrix::rotate f—
osg::Pl/2,1,O,O)
osg::Matrix::translate(一8,一1 0,一3)):
flightTransfOrm一>addChild(fireballAndSmoke);
参考文献
[1】http:fwww.openscenegraph.org.
//设置场景数据
viewer.setSceneData(rootNode):
[2]http:#www.nps.navy.mil/cs/sullivan/osgTutorials
(上接第35页)
//根据档案号码提出具体的二进制文件即归档的电子数据
setectblob cl 9 into:B DATA frOm dalist where c01=:
SDACODE using NowDB;
1 ‘l
dw 1.modify(…C+st ring(LFlNDROW)+“.protect=
end if
next
,,写入磁盘
讦fileexists(“c:WiewDA.psr”)then
end_f
end.f
filedelete(“c:WiewDA.psr“)
end-f
查是否可以进行档案编辑
LFOR=0
,/写入内存
gf
writebtobtofile(”cAViewDA.ps ̄',B_D rA)
_
select count( )into:LFOR from ostasystemvalue where
c01=:SServerUser and c02= 档案编辑 using NowDB;
if LFOR>0 thell
//装载至数据窗口
dw_1.setredraw(false)
dw
_
cb new.visible=true
cb
de1.visible=true
—
1.dataobject=Hc:WiewDA.psr“
dw
l。setredraw(true)
_
cb save.visible=true
cb new.enabled=true
cb save.enabIed=true
//dw_1.modifyf datawindow.print.preview=Yes“)
select c24 into:Stable frOm dalist where c01=:SDA-
CODE using NowDB;
_f LPPP>0 then
for LFlNDROW=1 to LPPP
If LFlNDROW<1 0 then
//执行定位
SWhere=mystrunit.S1
_
If SWhere<> then
dw 1.modiy(f“cO“+string(LFINDROW)+".pro-
tect=…0‘)
eIse
dw
1.modify(”c”+string(LFINDROW)+".protect=
_
_
for LF0R=I tO dw 1.rowcount()
LFINDROW=dw
1.find(SWhere,1,dw_t.rowcount0)
if LFtNDROW>1 then
dw
1.selectrow(LFINDROW,true)
_
0 }
end.f
next
dw
l。scro Itorow(LFINDROW)
_
end
next
end if
else
end if
select c24 into:S1 from datist where cO1;:SDACODE
usin}g NowDB
cb,new.visible=false
cb de1.visible=false
cb save.vis_bIe=faIse
cb new.enabIed=faIse
。
S1=UPPER(S1)
select c02 into:S1 from ostasystemvaIue where c01=:
S1 using NowDB;
cb save enabl.ed=faIse
.
阡lsnumber(S 1)then
end if
LPPP=tong(S1)
if LPPP>0 then
4结语
本档案系统采用C/S模式,用PB9结合MS SQL Server
2000设计开发实现,系统在扩展性方面也能比较自由地发挥,
达到了实际应用的要求。
{Or LFINDROW=1 to LPPP
|f LFINDROW<1 0 then
dw
_
1.mod_Ⅳ《 c0|I+string(LFINDROW)+“,pro-
tect='l ‘)
else
与
版权声明:本文标题:OSG的粒子特效仿真 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1710190537a561622.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论