32. OpenGL Particle Engine
Today we are going to be working with particle engines. The one here
is pretty basic but extremely easy to use and expand on. I have even
added texture masking for weirdly shaped particles. But unfortunately
I am yet to change the color of these on-the-fly without disrupting the
masking so for the moment, you cannot change the color to a number such as
0.1, 0.2, 0.3… it must be a whole number. Eg: 1 or 0.
Anyway, lets get on with the tutorial.
————————————————————————
Section 1: Variables
First off, we need to declare our header files. For this project we need
#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <math.h>
This first variable I am going to use to hold the number of particles
we will display on the screen at any one time.
const ParticleCount = 500
Of course we also need something to hold our textures.
GLfloat texture[10];
Now here, I am creating a Type called PARTICLES which will hold all
our information for our particles.
typedef struct
{
The X position
double Xpos;
The Y position
double Ypos;
The Z position
double Zpos;
The movement on the X axis while being displayed
double Xmov;
The movement on the Z axis while being displayed
double Zmov;
The amount of Red within the object
double Red;
The amount of Green within the object
double Green;
The amount of Blue within the object
double Blue;
The angle of rotation
double Direction;
How fast it accelerates upwards
double Acceleration;
How fast it decelerates downwards
double Deceleration;
How much we wish to scale it
double Scalez;
}PARTICLES;
And now we will create a variable that will hold each of the PARTICLES
information for each actual Particle
PARTICLES Particle[ParticleCount];
————————————————————————
Section 2: Creation
To create the particles I am going to call the function glCreateParticles
during the initialization section of the code with:
glCreateParticles
Now for the creation function:
void glCreateParticles (void) {
This will be a temporary variable to cycle through our particles
int i;
We are going to loop through our particles until we reach the end
for (i = 1; i < ParticleCount; i++)
{
Set the inital X position to 0
Particle[i].Xpos = 0;
Set the inital Y position to -5
Particle[i].Ypos = -5;
Set the inital Z position to -5
Particle[i].Zpos = -5;
Set the amount of movement on the X axis to a random number, we dont want
all our particles doing the same thing 😛
Particle[i].Xmov = (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005) – (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005);
Set the amount of movement on the Z axis to a random number, as above, we dont
want all our particles doing the same thing 😛
Particle[i].Zmov = (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005) – (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005);
Set the amount of Red to 1
Particle[i].Red = 1;
Set the amount of Green to 1
Particle[i].Green = 1;
Set the amount of Blue to 1
Particle[i].Blue = 1;
Scale the particle to 1 quarter of its original size
Particle[i].Scalez = 0.25;
Set the initial rotation angle to 0
Particle[i].Direction = 0;
Set the amount of acceleration to a random number so they climb to different
heights
Particle[i].Acceleration = ((((((8 – 5 + 2) * rand()%11) + 5) – 1 + 1) * rand()%11) + 1) * 0.02;
Decrease their acceleration by 0.0025. They will slow down at a constant
rate but you will not see a difference
Particle[i].Deceleration = 0.0025;
}
}
—————————————————————————-
Section 3: Updating the Particles
The particles would not be effective, if they stayed at their inital state, so
we want them to change and acctually move. I am doing this by calling:
glUpdateParticles in my Display function.
void glUpdateParticles (void) {
Once again, another temporary variable to handle the cycle through the particles
int i;
Loop through all of the particles
for (i = 1; i < ParticleCount; i++)
{
Set the color of the current particle
glColor3f (Particle[i].Red, Particle[i].Green, Particle[i].Blue);
Move the particle on the Y axes, adding on the amount of acceleration
and then subtracting the rate of deceleration
Particle[i].Ypos = Particle[i].Ypos + Particle[i].Acceleration – Particle[i].Deceleration;
Increase the deceleration rate so the particle falls gaining speed
Particle[i].Deceleration = Particle[i].Deceleration + 0.0025;
Move the particle on the X axis
Particle[i].Xpos = Particle[i].Xpos + Particle[i].Xmov;
Move the particle on the Z axis
Particle[i].Zpos = Particle[i].Zpos + Particle[i].Zmov;
Rotate the particle
Particle[i].Direction = Particle[i].Direction + ((((((int)(0.5 – 0.1 + 0.1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1);
Now here I am saying that if the particle goes beneath its initial height
which I set earlier to -5, then it will restart the particle changing some
of the variables.
if (Particle[i].Ypos < -5)
{
Set the X position
Particle[i].Xpos = 0;
Set the Y position
Particle[i].Ypos = -5;
Set the Z position
Particle[i].Zpos = -5;
Set the amount of Red
Particle[i].Red = 1;
Set the amount of Green
Particle[i].Green = 1;
Set the amount of Blue
Particle[i].Blue = 1;
Set the angle of rotation
Particle[i].Direction = 0;
Adjust the Acceleration rate to another random number
Particle[i].Acceleration = ((((((8 – 5 + 2) * rand()%11) + 5) – 1 + 1) * rand()%11) + 1) * 0.02;
Reset the Deceleration rate
Particle[i].Deceleration = 0.0025;
}
}
}
—————————————————————————-
Section 4: Drawing the Particles
To draw the particles, I am calling the following function: glDrawParticle
from within the Display function, after the updating function.
void glDrawParticles (void) {
Yet another temporary variable for our cycles
int i;
Looping through our particles again
for (i = 1; i < ParticleCount; i++)
{
Distinguish the start of our current particle, we do not wish for them
all to be affected by the ones prior
glPushMatrix();
Translate the particle on the X, Y and Z axis accordingly
glTranslatef (Particle[i].Xpos, Particle[i].Ypos, Particle[i].Zpos);
Rotate the particle
glRotatef (Particle[i].Direction – 90, 0, 0, 1);
Scale the particle
glScalef (Particle[i].Scalez, Particle[i].Scalez, Particle[i].Scalez);
Disable Depth Testing so our masking appears as one
glDisable (GL_DEPTH_TEST);
Enable blending
glEnable (GL_BLEND);
Set the blending function to Take our Destination Colour and combine it with
Zero which is Black
glBlendFunc (GL_DST_COLOR, GL_ZERO);
Bind our mask
glBindTexture (GL_TEXTURE_2D, texture[0]);
Draw our shape
glBegin (GL_QUADS);
glTexCoord2d (0, 0);
glVertex3f (-1, -1, 0);
glTexCoord2d (1, 0);
glVertex3f (1, -1, 0);
glTexCoord2d (1, 1);
glVertex3f (1, 1, 0);
glTexCoord2d (0, 1);
glVertex3f (-1, 1, 0);
glEnd();
Then set out blending function to combine White with White
glBlendFunc (GL_ONE, GL_ONE);
Bind our texture
glBindTexture (GL_TEXTURE_2D, texture[1]);
Draw the shape
glBegin (GL_QUADS);
glTexCoord2d (0, 0);
glVertex3f (-1, -1, 0);
glTexCoord2d (1, 0);
glVertex3f (1, -1, 0);
glTexCoord2d (1, 1);
glVertex3f (1, 1, 0);
glTexCoord2d (0, 1);
glVertex3f (-1, 1, 0);
glEnd();
Re-enable Depth Testing
glEnable(GL_DEPTH_TEST);
End the changes to the current object
glPopMatrix();
}
}
}
————————————————————————-
And there we have it, a simple particle engine that pumps out 500 particles
at a steady framerate of 80 frames per second.
If you have any questions, feel free to email me at swiftless@gmail.com
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. |
#include <GL/gl.h> #include <GL/glut.h> #include <windows.h> #include <stdio.h> #include <math.h> GLfloat texture[10]; const ParticleCount = 500; typedef struct PARTICLES Particle[ParticleCount]; GLuint LoadTextureRAW( const char * filename, int width, void square (void) { void glCreateParticles (void) { void glUpdateParticles (void) { glColor3f (Particle[i].Red, Particle[i].Green, Particle[i].Ypos = Particle[i].Ypos + Particle[i] Particle[i].Xpos = Particle[i].Xpos + Particle[i].Xmov; Particle[i].Direction = Particle[i].Direction + ((((((int if (Particle[i].Ypos < –5) } void glDrawParticles (void) { glTranslatef (Particle[i].Xpos, Particle[i].Ypos, Particle[i].Zpos); glBegin (GL_QUADS); glPopMatrix(); } void display (void) { void init (void) { glCreateParticles(); texture[0] = LoadTextureRAW( “particle_mask.raw”,256,256 void reshape (int w, int h) { int main (int argc, char **argv) { //function to load the RAW file GLuint LoadTextureRAW( const char * filename, int width, file = fopen( filename, “rb” ); data = (unsigned char *)malloc( width * height * 3 ); fread( data, width * height * 3, 1, file ); glGenTextures(1, &texture ); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, free( data ); return texture; void FreeTexture( GLuint texture ) |
I am trying to change this to act as a water fountain and I’m having a hard time making the particle have some sort of parabola behavior. Like it’ s kind of random at the moment.
I’m affecting this to limit the height and the width of the particle but it’s not working.
if ((Particle[i].Ypos 2) && (Particle[i].Xpos 1) && (Particle[i].Zpos 2)) //remake itself y-something instead of -5, create y and x and z bounds with ||
Someone please help please
Hi,
Just busy working through this tutorial and was just curious if it is intentional that you loop through your particles starting with i = 1 rather than i = 0?
I’m pretty new to openGL. I’ve compiled and run your code, but i’m not able to colour the particles separately. Either all are red, or all are blur and so forth. Please suggest a way to colour them separately. Thank you.
I’m pretty new to openGL. I’ve compiled and run yo the above code but the particles are all black and white. They don’t seem to get coloured. Could you please help me on this.
why the raw file cannot be loaded?tq
Thanks for writing these tutorials!!! I have worked my way through almost all of them now.
A question I have about this tutorial is that you mentioned that it runs at 80 frames per second but when I run this on my computer it is all a blur.
I added the line (and the library unistd.h):
usleep(10000 – glutGet(GLUT_ELAPSED_TIME)/1000) % 10000);
right before glutSwapBuffers();
I think this gets me to 100 frames per second, is there a better way to do this?
Thanks.
Hey Mark,
It will run at whatever speed your system will support. The best way to keep it all at a common speed is to switch to time based movement, so that everything you do is based on the current elapsed time. There is plenty of information on the Internet about this, but feel free to get back to me if you have any issues.
Cheers,
Swiftless
I have to say, big fan of your tutorials. This one in particular really made my day.
Best tutorials since Nehe. (I switched over to yours because you don’t use glaux)
Thanks.
Hello
Good tutorial.
Why you cannot change the color to 0.1, 0.2, 0.3… ?
it worked for me.
Aslam o alkum,, can you give me full tutorial of particle engine in opengl … because I am new in using opengl .. plz help me in this matter
Dude. Ive learnt alot from this site. Its sick. But, my particle system runs and no errors are coming up but the display is blank, just the black background. The warning messages ‘Cannot find or open the PDB file’, do come up but i heard that does’nt effect the program and i have no idea and don’t want to know about symbol servers at the minute. Can you help me? Seriously sick tutorials every other one, and I’ve nearly done all of them are sweet. Particle systems have a history of beating me, desperate to figure them out. Many Thanks.
Hey Sean,
That PDB message won’t effect the final output of the application. I’m not quite sure what could be causing the problem. My first guess would be, is it loading the textures correctly?
Cheers,
Swiftless
Oh, sorry 🙂 I think about cstdlib header file.
Hello! I think You should add line:
#include
for rand().