Click here to go straight to the WoS merchandise shop!

Rocket Club Developer Pages
Particle Systems

Rocket Club:
Home Page

Community:
Bulletin Board

Developer Pages:
Overview
Texture Assets
Animation

Developers:
Development_Notes

Synthetic Reality

So, What's a Particle System?

Rocket Club has its own idea as to what a particle system is, so my apologies to any particle system purists in the audience.

First, a picture:

This picture has a single particle system in it, one which is bound to an object (the fire is rising up out of the wooden disk below it). While not obvious from this still image, there is a constant stream of random fire boiling up and out. It's real pretty. In this particular image there are 40 'particles' at any given time. Each particle is born at the bottom, and rise upwards and enlargens and fades.

In Rocket Club, a particle system is defined by a special INI file in your "Particle" asset folder. For example:

rocket club/assets/00000001/Particle/00000001.campfire.ini

Where 00000001 is *my* developer serNum and you would add yours to your own folder. Feel free to rummage through my particle systems for ideas and possibly additional documentation.

But remember, the INI file defines a 'type of' particle system (fire, smoke, snow, etc) but it is your dna plan file which calls out which type of particle system (if any) which is to be used with that object.

Particles, Emitters, and Stages

A particle system is invisible until it has emitted some particles. Generally particles are emitted at some rate (which might vary over time) with some initial velocity and appearance. Particles then move according to some form of physics and evolve through different stages (the fire puff becomes smoke, the rain drop becomes a splash..)

A particle system has one or more emitters which define how new particles are generated.

When you hold a fourth of july sparkler, the hot end of the wire is the emitter, and the sparks are the particles. Gravity and thermodynamics provide the physics, and the particles go through the stages of 'glowing on wire', 'leaping as sparks', 'being pulled to the ground', 'becoming glowing embers', and 'fading out'

A campfire particle system might have one emitter for the flame, and another emitter for background smoke, and perhaps a third for the occasional popping ember. Individual particles may stay as fire and fade, or evolve into smoke. The physics might change with each stage, with fire rising quickly, embers affected by gravity, and smoke billowing outwards.

Individual particles eventually die and then are reborn as newly emitted particles, allowing the system overall to use a well-defined maximum number of particles. As a responsible particle system designer, you need to focus on keeping the particle count small and the physics computations simple.

The Particle System Texture Image, and Cells

Particle Systems are truly 3D in the sense that each particle has a real 3D position in the world. However, the image drawn at that point is actually a 2D 'billboard' (a 'square' image whose center is at the 3D point, but which is always/usually drawn 'facing' the camera)

The illusion of a solid 3D mass of plasma comes from the individual images not having hard outlines and thus their points of overlaps are not apparent. This also requires the use of 'alpha transparency' so that you can control how much one particle can be 'seen through' another. Over the lifetime of a particle, it's opacity will probably change. Most particles 'fade out' by having their opacity go completely transparent over time. Once the particle is completely transparent, it can be recycled without the viewer noticing it popping out of existence.

One axiom of a Rocket Club particle system is that each system has a SINGLE texture image associated with it. And generally that is a PNG file (since the PNG format is nicely compressed AND supports an 'alpha channel')

But before you freak out (how can I have smoke AND fire in the same particle system if there is only one image?), the texture image can be broken into 'cells' (the image file is actually a 2D array of images, with some number of rows and columns)

For example, here is a portion of the image file used for the example above:

This is four 'cells' (the actual image has more cells) and you can see the 'alpha' implied by the checkerboard background 'showing through' where the transparency is high. You won't see the checkerboard at runtime (this checkerboard is from Gimp)

Your emitter and stage configuration can descript which cell image to be used for an individual particle. This might be random, or you might vary it with stage or emitter, or you might even play the cells in order as a little cartoon over the life of the particle.

The actual Texture Images are in your Texture assets folder, like:

rocket club/assets/00000001/Textures/00000001.fire.png

Again, substitute your own serNum for the 00000001. In theory, you could use the same textures on your models, in theory. but you probably wouldn't want to.

If your particle image file does NOT have alpha in it, then you will see a bunch of square images with some background color, instead of nice soft particles.

Physics

I will probably add to this over time, but the physics of motion/change for individual particles include:

  • An initial position, relative to the emitter, specified by a 3D 'box' inside of which the particle is initially randomly placed. Collapse the box dimensions to zero to have all particles emitted at the same point
  • An initial velocity ('muzzle velocity') again specified by a separate 3D box whose dimensions define the max and min values for each of the 3 components of velocity (x, y, and z). Generally, Y is 'up' (opposite direction of gravity in any case)
  • A sensitivity to gravity (a value of 1.0 means earth normal gravity, pulling DOWN). Negative values push 'up'. Remember: gravity is not a velocity, it is an acceleration.
  • Possible ground collisions (particles can sense a ground collision, and change stage as a result). Only use this when needed, as it is reasonably expensive.
  • Radius Change. A particle can expand/shrink its "radius" (horizontal and vertical scale) over the lifetime of a stage
  • Opacity Change. A particle can vary its opacity from a start value to an end value over the lifetime of a stage.
  • Lifetime. A particle (stage) can have a finite lifetime (in seconds) after which the stage completes and the particle either dies or switches to a new stage.
Configuration Options in your Particle INI File

A PARTICLE Asset INI file has several sections in it

  • [Texture] defines the texture file asset and how many rows and columns it includes.
  • [General] identifies how many stage and emitter declarations there are
  • [StageN] declares the properties of stage N (N starts at 1, since stage 0 is death)
  • [EmitterN] declares the properties of emitter N (N starts at 0, just to confuse you)

Texture

[Texture]
name=00000001.glow.png
rows=1
column
s=1

General

[General]
numEmitters=1
numStages=3

Emitter Declaration

Stage Declaration

Binding to DNA Objects, and triggers

Triggers are un-documentable at this time, so we'll just cover the simplest case of an object (like a campfire) which just emits particles constantly.

Your object will already have a PLAN file, to which you will add the following:

[General]
name=Simple Campfire
...
numParticles = 1

[Particle0]
assetName=particle:00000001.campfire.ini

In the [general] section you add that 'numParticles' line indicating the number of particle systems used by that object (limited to one as of this writing)

Then in each [particleN] section, you define which particle system configuration file is to be used, and which node of the DNA to bind the emitters to. (use of anything but 'root' is not yet documented, so forget about that for now)

Eventually, I will tell you how to:

  • define 'meta node names' for emitters in the particle INI script (like 'exhaust')
  • define 'meta to actual' bindings in the PLAN file so as to pick up appropriate nodes from your model file (like 'engine exhaust should be emitted here, in this direction')
  • define rate 'triggers' for emitters (so engine exhaust can vary with accelerator value, for example)(or damage smoke can vary with % damaged)
Generating Particle Art

I won't kid you, I am not very good at this. I struggle with mapZone2 to get something useful. I know mapZone2 can do ANYTHING, but it's still hard for me. When you have been successful you have an image file in some format (bmp? jpg?) where beautiful flame/smoke/whatever plasma is on a black background.

I then make a NEW file, with a film-strip shape (say 1024 x 64 pixels to make one row of 16 columns) and make it solid black, then copy bits of the beautiful flame into individual cells (the original image being a bunch of individual flamey bits) nicely centered for my needs.

So that's:

  • By hook or by crook, a single file with beautiful things scattered at random on a black background
  • Copied to a filmstrip file where individual flames are centered in their own cells
  • Converted to a PNG file with an alpha layer that makes the black completely transparent, and 'dim' colors semi-transparent.
Getting an Alpha Channel from Source Art without One

So, you have generated a beautiful filmstrip of images in a single file with a black background. Keep that file around forever, as you might need to edit it someday. But now we need to make a PNG file with that black background turned into alpha transparency (and the 'dimmer' parts of the image to be SEMI_transparent).

Let's pretend your original file is a JPG and the final file will be a PNG. And that you are using GIMP

1.) start GIMP
2.) Load source.JPG
3.) From the LAYERS/MASK menu, select "Add Layer Mask"
4.) From the dialog that appears, select 'gray scale' then OK
5.) At this point the black background should be gone, and you should see a checkerboard 'through' the image
6.) From the LAYERS/MASK menu, select "Apply Mask"
7.) No obvious change appears in the image, but you have copied the layer mask to the alpha channel of the image, and deleted the layer mask.
8.) From the FILE menu, SAVE AS... 0000001.myTexture.png

And, of course, use your own serial number. Copy the file to your assets/TEXTURES folder.

Debugging without going crazy

It can be tedious having to restart the game and travelling to some location every time you tweak some configuration value in your particle script, so I added a command to the DEBUG menu. It is currently the 'reload scripts' command and it causes all action scripts and particle definitions to be reloaded.

So, on a good day, you drop an object with your particle system on it, decide what you need to change, then, without stopping the game, edit the particle .ini file, save the changes and select 'reload scripts' to have it take effect.

You can also spot-test a particle system by using the 'play' command, by typing:

/play particle:00000001.campfire.ini

Where you provide the name of the particle asset you want to try. For particle systems which are intended to be bound to a DNA object, this can be a little odd. Probably your avatar will be used as the source object.

You can make your own macros for things you do a log, like, say:

/fog=/play particle:00000001.fog1.ini

Then later you just type "/fog" to play that. The 'play' command is just for you, no one else sees the particles you are playing.

Sharing Particles

At some point the peer to peer file system will automatically share the PARTICLE assets and their attendent texture images. That may be spotty right now, my apologies.

Example: Fire from a point

Generates particles in a small box, let's them float up and out and fade

[texture]
name=00000001.flame3.png
rows=1
columns=16
blendMode=1

; There must be at least one emitter (max of 16) and one stage (max of 16)

[General]
numEmitters=1
numStages=1

[stage1]
name=puff
lifeTime = 3.0
gravity = -0.1
startOpacity = 1.0
endOpacity = 0.0
startRadius = 0.2 ; percent of emitter start radius
endRadius = 2.0

; this is a random box emitter, particles start at some random spot in the box

[emitter0]
name=box
node=root
movementMode=0
stage=1
startRate = 1.0
spawnRate = 10
maxParticles = 80
posScale= 0.3
minPosX = -0.1
maxPosX = 0.1
minPosY = 1.0
maxPosY = 1.2
minPosZ = -0.01
maxPosZ = 0.01
velScale= 0.1
minVelX = 0.0
maxVelX = 0.0
minVelY = 1.0
maxVelY = 1.01
minVelZ = 0.0
maxVelZ = 0.0
radiusScale = 1.0
minRadius = 0.5
maxRadius = 1.5
minCell = 0
maxCell = 3

Example: Fog in an Area

Large blobs appear in a large area, then fade

[texture]
name=00000001.glow.png
rows=1
columns=1
blendMode=1
sort=0
minCamDist = 2.0
wrapDist = 100.0

; There must be at least one emitter (max of 16) and one stage (max of 16)

[General]
numEmitters=1
numStages=2

[stage1]
name=fadeIn
stageOnTimeOut=2
lifeTime = 1.0
gravity = 0.0
startOpacity = 0.0
endOpacity = 0.8
startRadius = 1.0
endRadius = 1.0

[stage2]
name=expandAndFade
stageOnTimeOut = 0
lifeTime = 9.0
gravity = -0.1
startOpacity = 0.8
endOpacity = 0.0
startRadius = 1.0
endRadius = 3.0


[emitter0]
name=box
node=camera
stage=1
startRate = 1.0
spawnRate = 100.0
maxParticles = 1000
posScale= 50.0
minPosX = -1.0
maxPosX = 1.0
minPosY = -0.3
maxPosY = 0.3
minPosZ = -1.0
maxPosZ = 1.0
velScale= 1.0
minVelX = -0.1
maxVelX = 0.1
minVelY = -0.1
maxVelY = 0.0
minVelZ = -0.1
maxVelZ = 0.1
radiusScale = 3
minRadius = 0.5
maxRadius = 2.5

Example: Snow

Zillions of tiny flaks all around the camera (this is expensive, due to the zillion)

[texture]
name=00000001.glow.png
rows=1
columns=1
wrapDist = 50.0

; There must be at least one emitter (max of 16) and one stage (max of 16)

[General]
numEmitters=1
numStages=2

[stage1]
name=flake
stageOnCollision=2
lifeTime = 7.0
gravity = 0.0
startOpacity = 0.5
endOpacity = 0.5

[stage2]
name=onGround
stageOnTimeOut = 0
lifeTime = 3.0
gravity = 0
startOpacity = 1.0
endOpacity = 0.0
deltaVelY = 0.0

[emitter0]
name=box
node=camera
stage=1
startRate = 1.0
spawnRate = 200.0
maxParticles = 2000
posScale= 10.0
minPosX = -1.0
maxPosX = 1.0
minPosY = 0.0
maxPosY = 1.0
minPosZ = -1.0
maxPosZ = 1.0
velScale= 1.0
minVelX = -0.1
maxVelX = 0.1
minVelY = -1.0
maxVelY = 0.0
minVelZ = -0.1
maxVelZ = 0.1
radiusScale = 0.1
minRadius = 0.5
maxRadius = 1.5

Example: Hail

This example has hard particles which fall rapidly in a straight line until they hit the surface, at which point they 'bounce' by going through a couple extra stages with an inversion of Y velocity on each bounce.

[texture]
name=00000001.glow.png
rows=1
columns=1

[General]
numEmitters=1
numStages=3

[stage1]
name=falling
stageOnCollision=2
lifeTime = 7.0
gravity = 0.0
startOpacity = 1.0
endOpacity = 1.0

[stage2]
name=firstBounce
stageOnCollision=3
stageOnTimeOut = 0
lifeTime = 3.0
gravity = 1.0
startOpacity = 1.0
endOpacity = 1.0
deltaVelX = 10.0
deltaVelY = -0.8
deltaVelZ = 10.0

[stage3]
name=secondBounce
stageOnCollision=0
stageOnTimeOut = 0
lifeTime = 3.0
gravity = 1.0
startOpacity = 1.0
endOpacity = 0.0
deltaVelX = 1.0
deltaVelY = -0.8
deltaVelZ = 1.0

; this is a random box emitter, particles start at some random spot in the box

[emitter0]
name=box
node=camera
stage=1
startRate = 1.0
spawnRate = 200.0
maxParticles = 2000
posScale= 10.0
minPosX = -1.0
maxPosX = 1.0
minPosY = 0.0
maxPosY = 1.0
minPosZ = -1.0
maxPosZ = 1.0
velScale= 1.0
minVelX = -0.1
maxVelX = 0.1
minVelY = -8.0
maxVelY = 0.0
minVelZ = -0.1
maxVelZ = 0.1
radiusScale = 0.03
minRadius = 1.0
maxRadius = 1.0

  Copyright 1999-2014, Synthetic Reality Co. All Rights Reserved