Hallo,
I while ago I started a post about doing fluid simulation. I have now started my quest. As I have limited programming experience I decided to start with something more simple, a 2d particle system. That way I can see how drawing is done and how to handle a massive amount of particles. Also, is it ok to post this kind of things here? I see that most of the questions are very advanced and not much code is posted at all, if the forum is not meant for this kind of thing I am doing, please delete this thread.
Anyway, I have gotten the basic to work, but there are some buggs that I need some help with removing:
-
The particles are forming a square. This makes no sense to me, as the velocity should make them move a equal distance away from where they are created. Should not the form formed be a circle? To make it a bit more clear I have made a small picture:
If you look at this picture you see that the particles are only living inside the red square, but should it not be inside the blue circle?

-
How do I make a rate controle, like there is in e.g Autodesk Mayas particle system? Right now all of my particles are created at ones (made it look a bit more interesting with a random lifespan)
-
If something else is all wrong let me know
Here is my code:
Note: void particleUpdate(); is the only interesting thing, the rest is super basic openGL and other basic stuff, but I am posting the whole thing anyway.
Compiled on windows XP SP 2, with DEV-C++
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glut.h>
#include <fstream>
#include <math.h>
#include <stdlib.h>
#define MAX_PARTICLES 1000
//------Global variables
static GLfloat EmitterPosX = 0;
static GLfloat EmitterPosY = 0;
//------Global variables /end
//------Functions
void display(void);
void particleInit(int i);
void particleUpdate();
void limitFrameRate(double lastTime, float frameRate);
//------Functions /end
// ---------------------------------------------------------------
// Create the particle system
// ---------------------------------------------------------------
struct particle
{
float lifeSpan;
float age;
int number;
bool alive;
float mass;
float inv_mass;
//position
float posX;
float posY;
//velocity
float vX;
float vY;
//acceleration
float aX;
float aY;
//forces
float fX;
float fY;
};
//Create the particle variable.
//It is created as an array, where
//one particle is a member of the array.
particle particle[MAX_PARTICLES];
// ---------------------------------------------------------------
// Create the particle system /end
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// Update the particle system.
// The function is made like this:
//
// * First check if its ok do make a new fram(limit the frameRate)
// * Check if the particle is alive
// * Update the particle
// ---------------------------------------------------------------
void particleUpdate()
{
//First we check if its ok to update the system
//--------------------------------------
//Variable for holding the wanted frameRate
//because of the time function we have to use this
//formula: FrameRate = 1000 / wantedRate
float wantedRate = 100.0; //Should be a global variable?
float frameRate = 1000/wantedRate;
limitFrameRate(timeGetTime(), frameRate);
//Find the timestep, which is the time between
//two frames/duration of one frame
float timeStep = 1.0/frameRate;
//Variables for controling the particles:
//--------------------------------------
//Force will be how much the particle moves per frame in
//units, so a high value will make the particles move
//extremly fast. Force is constant for all particles,
//atleast until I get the basic to work.
//This part will be removed later, as it is not very good
float forceX = 0;
float forceY = 0;
//Update the particles
//--------------------------------------
//VelocityY += ForceY / mass * timestep;
//PositionY += VelocityY * timestep;
for (int i=0; i <MAX_PARTICLES; i++)
{
//if the particle is alive, update the position and other
//variables
if (particle[i].alive == TRUE)
{
float forceX = 0;
float forceY = 0;
//update velocity
particle[i].vX += (forceX * particle[i].inv_mass) * timeStep;
particle[i].vY += (forceY * particle[i].inv_mass) * timeStep;
//update position
particle[i].posX += particle[i].vX * timeStep;
particle[i].posY += particle[i].vY * timeStep;
//Update the age and lifetime of the particle
//if it has lived for to long, kill it
if (particle[i].age <= particle[i].lifeSpan)
{
//age is how many frames it has been alive (is time better?)
particle[i].age += 1/wantedRate;
}
else
{
particle[i].alive = FALSE;
}
}
//When the particle is dead, restart it at default position
//with default values
if (particle[i].alive == FALSE)
{
particleInit(i);
}
}
}
//When a particle is dead, this proc will make it alive again
//-----------------------------------------------------------
void particleInit(int i)
{
//this function will be used when a particle is dead.
//It will restore the particle at a dufault position
//ready to be used again
//Particle info
particle[i].lifeSpan = ((rand() % 100)/100.0) + 0.005 ; //in sec
particle[i].age = 0;
particle[i].alive = TRUE;
particle[i].number = i;
particle[i].mass = 1; //in KG
particle[i].inv_mass = 1/particle[i].mass;
//Particle position
particle[i].posX = EmitterPosX;
particle[i].posY = EmitterPosY;
//Velocity
//This is where initial velocity can be added
float value = -0.5 + ((rand() % 110) / 100.0) ;
float value2 = -0.5 + (rand() % 110) / 100.0;
particle[i].vX = sin(value / 10.0);
particle[i].vY = sin(value2 / 10.0);
//acceleration(m/s)
particle[i].aX = 0;
particle[i].aY = 0;
//forces(newtons)
particle[i].fX = 0;
particle[i].fY = 0;
}
// ---------------------------------------------------------------
// Update the particle system.
// ---------------------------------------------------------------
//-------Main
int main(int argc,char **argv)
{
glutInit(&argc,argv);
// Set window size
glutInitWindowSize(512,512);
//display mode
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutCreateWindow("OpenGL window");
srand(timeGetTime());
//Particle stuff
//Sett the particles to defaul
for (int i=0; i <MAX_PARTICLES; i++)
{
particleInit(i);
}
//Update the particles
glutIdleFunc(display);
// Register a display callback function for window repaints.
glutDisplayFunc(display);
// Enter the GLUT main event processing loop.
glutMainLoop();
return 0;
}
//-------Main /end
//-------Display
//Used to draw whatever you want
void display(void)
{
// Clear the buffers currently enabled for color writing.
glClear(GL_COLOR_BUFFER_BIT);
//Zoom in and out
//how to?
// Default matrix stack is the modelview matrix stack.
glLoadIdentity();
// Draw a quad which will represent the emitter
/*
glBegin(GL_QUADS);
glVertex3f((+0.1f + EmitterPosX),(+0.1f + EmitterPosY),(0.0f));
glVertex3f((-0.1f + EmitterPosX),(+0.1f + EmitterPosY),(0.0f));
glVertex3f((-0.1f + EmitterPosX),(-0.1f + EmitterPosY),(0.0f));
glVertex3f((+0.1f + EmitterPosX),(-0.1f + EmitterPosY),(0.0f));
glEnd();
*/
//Update the particles before we draw them
particleUpdate();
//Draw each particle
for (int i=0; i <MAX_PARTICLES; i++)
{
glBegin(GL_QUADS);
glVertex3f((+0.01f + particle[i].posX),(+0.01f + particle[i].posY),(0.0f));
glVertex3f((-0.01f + particle[i].posX),(+0.01f + particle[i].posY),(0.0f));
glVertex3f((-0.01f + particle[i].posX),(-0.01f + particle[i].posY),(0.0f));
glVertex3f((+0.01f + particle[i].posX),(-0.01f + particle[i].posY),(0.0f));
glEnd();
}
// Perform a buffer swap on the layer in use for the current window
// (an implicit glFlush is done by glutSwapBuffers before it returns).
glutSwapBuffers();
}
//------Display /end
//------limit the frameRate
void limitFrameRate(double lastTime, float frameRate)
{
double currentTime;
while (currentTime < frameRate)
{
currentTime = (timeGetTime() - lastTime);
}
}
