The Big Picture
OpenGL is a powerful graphical library, which can be used to render some amazing effects. Despite the great power of the library, it can be a great hassle to create particle effects. The included particle engine is intended to greatly simplify the creation of such effects. The code offered here is far from perfect, but it is a merely a start to this endeavor. Any suggestions, ideas, or modifications of this code are welcome.
The concept of particle effects is very simple. Particle effects can be used to simulate fire, fireworks, water fountains, snow, rain, explosions and many other things. The effects are created by creating a definite number of particles. Depending on the need for performance and realistic appearance, the number of particles can range from 50 to thousands. Each particle has its own location, size, velocity, color, life and image. The particle engine controls the particles and makes them react according to the rules of the particle itself.
As the particles fade away, the particle engine is alerted that the particle is dead. Once all the particles die, the effect will stop, or if as the engine is alerted that the particles are dead, it can reinitialize it and it can be displayed again. You may wish to look at the fire demo of this particle engine. It uses glut[^] to simplify the Windows programming aspect of the demonstration, and the actual particle engine does not rely on it in any way.
An Overview of the Particle
The particle is encapsulated in
QdParticle and is used by the
QdParticleEngine. The particle engine is used to manipulate the particles and their variables. The variables that the particles have control their behavior, and after the particles are initialized, they should not be changed manually. Below is a list of
QdParticleEngine's member functions to manipulate the data stored in the particles.
QdParticleEngine's member functions.
|Sets the color to change to prior to the particle is drawn. The color of the particle will be determined through this and the colors of the bitmap.|
|Each time the particle is updated the current color becomes its previous value plus the value of the color given.|
|Each time the particle is update its coordinates become their previous value plus the value of the value given.|
|The force of gravity is similar to the direction, except as the age of the particle increases its effect does too. If the direction is set with positive Y values, and gravity is set with small negative Y values the particle will rise, slow down, and then fall.|
|Sets initial position of the lower right corner.|
|Sets initial position of the upper left corner.|
|Sets age for computation of the effect of gravity. When particle is initialized it should be set to 0.|
|The gravity factor can make gravitational forces stronger or weaker.|
|Sets how alive the particle is. When the life value is 0 the particle is "dead".|
|Sets what value should be added to the life each time the particle is updated. Should be negative values.|
The particles are created in an array of particles on the heap with the function
init(nParticles). The parameter is the number of particles to exist in the array. When the engine is deconstructed it deletes these particles off the heap. The init function can only be called once. The greater the number of particles the engine controls the slower the effect will go at its maximum speed.
Creating Your Own Engine
Create a class to encapsulate the effect, inheriting from
QdParticleEngine. Add any variables that your engine would use and use its constructor to initialize these variables as needed. The virtual functions
particleDead should be used to set the variables of the individual particles.
resetParticles() function is called initially, and can be called more times to bring the particles to the position they were initially. Because random number generation is used to give values to the variables in this, the default random number generator needs to be seeded:
Now it is required to fill the particle variables with information about how to react as time goes by. In the demo included, the initialization that each particle will undergo will be the same as when each particle fades into nothing and is re-initialized with data. I could copy and paste a lot of code, but besides being bad practice, it is more work for me to do. The solution is to call the
particleDead() function for each particle.
while(nCount != m_nParticles)
m_nParticles is set by the function
init(nParticles) and needs not to be manually altered with. This function can easily initialize the particles in a way that is completely unrelated to the
particleDead(nParticle) function, the fire engine though, is more logically connected with it.
particleDead() function is called whenever the particle's
m_fLife variable is less than 0. This variable changes consistently over time by initializing it with the
setLifeFade() variables. Also when a particle is re-initialized it is important to set the frame and age to 0. The
setAge function should be used accordingly. If these functions are not called, unusual effects will occur with the gravity variables.
In the fire engine, a non-default constructor was used to set the initial color of the particles. Constructors and variables within the particle engine can be used for things like this, or for other reasons that fit.
Particle Bitmap Path
By default the bitmap used for each of the particles is called particle.bmp, but the path can be changed. Before the particle engine calls the
init() function, call the function
setImgPath(). If the path given to the engine is incorrect, if the image isn't a valid bitmap, or if for some other reason the engine cannot use the bitmap, upon initialization the executable could display a not so helpful error message:
Error Message: Bitmap not Valid
Particles That Can Overlap
To make most particle effects work, and allow the particles to overlap each other without erasing the picture created earlier, the engine needs to make part of the particle transparent. The transparent part of the particle is denoted on the bitmap of the particle by the color black. To make the color black transparent on the particles, the following code should be added prior to the displaying of the particles.
Setting Limits For the Particle
When particles leave the viewing window, they can be reinitialized by setting limits for the particle. The function
setLimit(fLimitL, fLimitR, fLimitT, fLimitB) sets just such boundaries. It can be called any time during the engine's life. Disabling the boundaries can easily be done.
The texture engine included, which the inner workings of the particle engine requires, was also created by me and can be freely distributed with the particle engine in any project you choose to use it in. The texture engine works with this example, yet may not work in a variety of other situations. Make sure you include texture.cpp and texture.h or errors will occur in the compiling.
Feel free to leave any questions or comments, and if you create any engines of your own off of this I would be interested to see it.