Particle systems

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:

  1. Creating a project
  2. Setup of model, camera and render loop
  3. Creating a particle emitter
  4. List of emitter types
  5. Adding a particle affector
  6. List of affector types

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.

1. Creating a project

First we create a project and compiler options XML file. (See Render loop for a more detailed description of creating a project.)

  1. Create a new project through the Project menu.
  2. Right click on project's top level tree node named "New GBP(Unsaved)" and select Rename folder. Rename the folder to "Particles".
  3. Save the project as "ParticleSystem.gbp" from the Project menu.
  4. Add a new file to the project tree and save it as "EngineEffect.gbc"
  5. Add a new file to the project tree and save it as "Particles.xml". (The XML file must have the same name as the top level tree node.)

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>

2. Setup of model, camera and render loop

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()
}

3. Creating a particle emitter

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:

4. List of emitter types

The following particle emitters are included in Irrlicht:

5. Adding a particle affector

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.

6. List of affector types

The following particle affectors are included in Irrlicht:

Attraction affector
Modifies the positions of the particles and attracts them to a specified point at a specified speed per second.
Fade out affector
Gradually modifies the color of every particle. The final color is reached by the end of a particle's MaxLifeTime.
Gravity affector
Modifies the direction of particles and accelerates them in a specified direction with a specified force.
Rotation affector
Modifies the positions of particles and attracts them to a specified point at a specified speed per second.
Scale affector
Scales particles to a multiple of their size.