The human brain is exceptionally good at spotting patterns and repetitions. Explosions, rain, smoke or fire created using a fixed set of animations would look unrealistic. To convincingly replicate the seemingly random nature of "fuzzy" phenomena a modelling technique called Particle Systems was developed by W. T. Reeves at Lucasfilm. A particle system consists of an emitter and an optional affector. Particle emitters are the source of the particles (which are images), and its location determines where they are generated and where they move to. Particle affectors can be added to control the trajectory or appearance of the generated particles. In this tutorial we will be adding particle emitters to a space ship model to create an engine thrust effect. The following topics are covered in this tutorial:
The tutorial's code files and media files are installed along with Ginjo-Builder and can be accessed from the 'Project' window that is shown when the editor starts. This tutorial is called '15_ParticleSystems' in the 'Tutorials' tab.
First we create a project and compiler options XML file. (See Render loop for a more detailed description of creating a project.)
Open "Particles.xml" and just like in Render loop add the <exe> and <startup> elements. We will also import the GB namespace so we don't have to type it out every time. (For the full list of XML tags see Compiler options.)
<?xml version="1.0" encoding="utf-8"?> <root> <exe path=".\game.exe" /> <startup name="EngineEffect.main" /> <ImportSymbols> <namespace name="GB" /> </ImportSymbols> </root>
In our XML file we specified the startup function as "EngineEffect.main". Double-click on "EngineEffect.gbc" in the project tree to open it, and add the following function, called "main". (When you run your program this is the function where execution starts.) Initialize the Irrlicht 3D engine and add the space ship model as in the code below. In this tutorial we do not have any lights, thus the Lighting material flag of the model must be turned to false. (Otherwise the model will be completely black.)
function main(var:string cmdArgs[]) returns Int32 { var:gb.IrrlichtCreationParameters options=new gb.IrrlichtCreationParameters() //Without anti-aliasing our model edges would be jagged options.AntiAliasing=255 //Tell Irrlicht to use OpenGL for graphics options.DriverType=gb.video.DriverType.OpenGL //Turn off logging, we won't be using it for now options.LoggingLevel=gb.LogLevel.None var:gb.IrrlichtDevice engine = gb.IrrlichtDevice.CreateDevice(options) //Also set our window's title engine.SetWindowCaption('Skeletal animation') var:video.VideoDriver driver=engine.VideoDriver var:Scene.SceneManager smgr=engine.SceneManager //load model from relative path ..\media\SciFi_Fighter_AK5.dae var:scene.AnimatedMesh ShipMesh = smgr.GetMesh('..\media\SciFi_Fighter_AK5.dae') //add model to scene var:Scene.MeshSceneNode SpaceShip = smgr.AddMeshSceneNode(ShipMesh) if(!isNull(SpaceShip)){ SpaceShip.Scale = new core.Vector3Df(0.03) SpaceShip.SetMaterialFlag(video.MaterialFlag.Lighting, false) } }
Next add a Maya camera from the cameras tutorial and the render loop to the "main" function exactly as in the first tutorial.
var:gb.scene.CameraSceneNode Camera= smgr.AddCameraSceneNodeMaya() camera.Position=new core.Vector3Df(300) camera.Target=SpaceShip.Position var:video.Color background=new video.Color(160, 160, 160) while (engine.Run()){ driver.BeginScene(video.ClearBufferFlag.All, background) smgr.DrawAll() driver.EndScene() }
We are going to create four particle systems, one for each of the four engine exhaust ports of the model. By default AddParticleSystemSceneNode creates a point emitter. However, we are going to set the first parameter of the function call to false so that a default emitter is not created. The second parameter is the parent node of the particle system. We specify our space ship scene node as the parent, thus the position of the particle system will be relative to the position of the space ship scene node. Update the models code block as follows:
if(!isNull(SpaceShip)){ SpaceShip.Scale = new core.Vector3Df(0.03) SpaceShip.SetMaterialFlag(video.MaterialFlag.Lighting, false) var:scene.ParticleSystemSceneNode PS1 = smgr.AddParticleSystemSceneNode(false,SpaceShip) var:scene.ParticleSystemSceneNode PS2 = smgr.AddParticleSystemSceneNode(false,SpaceShip) var:scene.ParticleSystemSceneNode PS3 = smgr.AddParticleSystemSceneNode(false,SpaceShip) var:scene.ParticleSystemSceneNode PS4 = smgr.AddParticleSystemSceneNode(false,SpaceShip) }
Just like the scene manager creates scene nodes, an instance of a particle system can create emitters. In the following code we create a cylinder emitter and set some of its properties. The Direction property determines not only the direction the particles are emitted in, but also their speed. Add the following code inside the space ship's code block after the particle systems:
var:scene.ParticleCylinderEmitter E1=PS1.CreateCylinderEmitter(new core.Vector3Df(0), 30, new core.Vector3Df(1,0,0),0.2) E1.Direction=new core.Vector3Df(0,0,-0.1) //direction and speed of particles E1.MinParticlesPerSecond=500 E1.MaxParticlesPerSecond=8000 E1.MinLifeTime=1000 //in milliseconds E1.MaxLifeTime=3000 //in milliseconds
Now that we have an emitter we need to assign it to the particle systems. We can reuse the same emitter as many times as we need. Continue the space ship models code with the following:
var:video.Texture exhaust = driver.GetTexture('..\media\exhaust.bmp') PS1.Emitter=E1 PS1.SetMaterialTexture(0, exhaust) PS1.SetParticleSize(new core.Dimension2Df(1)) PS1.SetMaterialType(video.MaterialType.TransparentAddColor) PS1.SetMaterialFlag(video.MaterialFlag.Lighting, false) PS1.Position=new core.Vector3Df(-280,-240,-900) PS2.Emitter=E1 PS2.SetMaterialTexture(0, exhaust) PS2.SetParticleSize(new core.Dimension2Df(1)) PS2.SetMaterialType(video.MaterialType.TransparentAddColor) PS2.SetMaterialFlag(video.MaterialFlag.Lighting, false) PS2.Position=new core.Vector3Df(-280,240,-900) PS3.Emitter=E1 PS3.SetMaterialTexture(0, exhaust) PS3.SetParticleSize(new core.Dimension2Df(1)) PS3.SetMaterialType(video.MaterialType.TransparentAddColor) PS3.SetMaterialFlag(video.MaterialFlag.Lighting, false) PS3.Position=new core.Vector3Df(280,240,-900) PS4.Emitter=E1 PS4.SetMaterialTexture(0, exhaust) PS4.SetParticleSize(new core.Dimension2Df(1)) PS4.SetMaterialType(video.MaterialType.TransparentAddColor) PS4.SetMaterialFlag(video.MaterialFlag.Lighting, false) PS4.Position=new core.Vector3Df(280,-240,-900)
When you run the program you will see the following:
The following particle emitters are included in Irrlicht:
Particle affectors can be used to control the trajectory or appearance of the generated particles. As with the emitter we use an instance of a particle system to create an affector. Append the following the space ship's code block to create a scale affector that scales the particles to double their size as by the end of their MaxLifeTime.
var:scene.ParticleAffector PSScale=PS1.CreateScaleParticleAffector(new core.Dimension2Df(2)) PS1.AddAffector(PSScale) PS2.AddAffector(PSScale) PS3.AddAffector(PSScale) PS4.AddAffector(PSScale)
Note that you can use the IntelliDoc Symbol Info feature to look-up symbol types and definitions. The 'lightbulb' button on the toolbar looks-up the symbol type for the current cursor location and displays it in a tooltip. Pressing F1 also shows the tooltip.
The following particle affectors are included in Irrlicht: