20
www.fullonsoftware.co.uk 08 OpenGL Particle Systems Using PointSprites, Textures and Blending in Microsoft Visual C++ 2008 Express Edition Richard Sabbarton

OpenGL - Particle System Tutorial - Blending - Point Sprites

Embed Size (px)

Citation preview

Page 1: OpenGL - Particle System Tutorial - Blending - Point Sprites

www.fullonsoftware.co.uk

08

OpenGL Particle Systems Using PointSprites, Textures and Blending in

Microsoft Visual C++ 2008 Express Edition

Richard Sabbarton

Page 2: OpenGL - Particle System Tutorial - Blending - Point Sprites

Contents Introduction ............................................................................................................................................ 3

Prerequisites ....................................................................................................................................... 3

Setting up our Particle functions ............................................................................................................ 4

Rendering Points (GL_POINTS) ............................................................................................................... 4

Initial Translation ................................................................................................................................ 4

Draw Points ......................................................................................................................................... 4

Creating the Particle System ................................................................................................................... 6

Setting a Constant for MAX_PARTICLES ............................................................................................. 6

Defining our Particle Structure ........................................................................................................... 6

Float X,Y,Z ........................................................................................................................................ 6

Float sX, sY, sZ, tX, tY, tZ .................................................................................................................. 6

Float R,G,B ....................................................................................................................................... 7

Bool Active ...................................................................................................................................... 7

Int Age and MaxAge ........................................................................................................................ 7

Int BounceCount ............................................................................................................................. 7

Particles[MAX_PARTICLES]; ............................................................................................................ 7

Initialising the Particles ........................................................................................................................... 7

Activating the Particles ........................................................................................................................... 8

Adjusting the Particles ............................................................................................................................ 9

Rendering the Particles ......................................................................................................................... 10

Changing Colours .................................................................................................................................. 11

Using Textured Quads instead of Points ............................................................................................... 13

Loading the Bitmap Texture .............................................................................................................. 13

Rendering Quads as Points ............................................................................................................... 14

Adding a plane to bounce off ................................................................................................................ 17

Adding Reflection of the particle system .............................................................................................. 19

Page 3: OpenGL - Particle System Tutorial - Blending - Point Sprites

Introduction The scope of this document is to introduce beginners and newbie developers (of which I am most

certainly one) to some of the concepts and ideas that I have used during the process of learning to

develop 3D applications and games using Microsoft Visual C++ 2008 Express Edition and OpenGL.

In this document I will cover the requirements for creating a simple particle system that can be used

to create nice visual effects for your 3D projects. This example will create a particle system that fires

particled upwards from a single point of origin. The particles will rise, fall and then bounce a couple

of times before disappearing ready to be fired again.

Prerequisites In order to paste and compile the code and follow the examples in this document you will need to

download and install the following components:

Microsoft Visual C++ 2008 Express Edition

Microsoft Platform SDK

Both of these can be downloaded from the Microsoft Website free of charge. Details on

downloading, installing and setting these up is available on MSDN and there are some snippets

entries and details on the my website (www.fullonsoftware.co.uk/snippets/snippets.asp)

It is also assumed that you have created a simple OpenGL Application that is ready for code and

rendering a blank screen. There is a simple OpenGL Application Template and details on setting up

the Visual Studio Project also posted on snippets.

IMPORTANT NOTE

I am not a professional developer. I am a hobby coder that has struggled through internet tutorials

to learn what I have. Although the code I have generated will compile and works it may not

represent industry standards and it is certainly possible that there are better ways of performing the

some functions. One of the biggest problems I had was finding good quality and easy to understand

tutorials to show me how to do stuff. This is one of the main reasons for wanting to write this guide.

I want to group together some of the knowledge that I have gained from online tutorials and

development experience into one place. I hope it helps to get people started.

Page 4: OpenGL - Particle System Tutorial - Blending - Point Sprites

Setting up our Particle functions The first thing I want to do is to use a standard set of functions that I can refer to through the rest of

this document. The Project File has been posted into Snippets on www.fullonsoftware.co.uk and

these functions will be defined in that project. The Project on the website is based on the OpenGL

Application Template which is also posted on snippets if you want to follow through this guide.

You should create the following functions in your main.cpp file:

void InitParticles();

This should be called ONCE during your application initialisation. We will use it to setup our particle

array ready for activation, animation and rendering.

void ActivateParticles();

void AdjustParticles();

void RenderParticles();

These three functions should be called in this order for every frame rendered. You may want to put

ActivateParticles() and AdjustParticles() in your PrepareGLScene() function or equivalent and the

RenderParticles() function should be called from your DrawGLScene() function.

Now that you have created these functions it is time to make sure our code is working correctly...

Rendering Points (GL_POINTS) Before we get started creating our particle system let’s start by simply rendering a few points on

screen. We’ll start by adding a line of code in your DrawGLScene function just before your call to

RenderParticles().

Initial Translation We need to translate into the GL World so that we can see what we are rendering. Add the

following line before your RenderParticles() call:

glTranslatef(0.0f, -1.0f, -10.0f);

This will move our origin 10 into the scene and down 1. This should move everything we render

from here on into our field of view so that we can see it all. These are good values to start with, we

can adjust them later if we need to.

Draw Points Initially we will use GL_POINTS to render our Particle System. Once we have it working we will look

at adding textures, enabling blending and simple reflections but let’s not run before we can walk.

Let’s add a few lines to our RenderParticles() functions so that it looks like this:

Page 5: OpenGL - Particle System Tutorial - Blending - Point Sprites

void RenderParticles(){

glColor4f(1.0f, 1.0f, 1.0f, 0.5f);

glBegin(GL_POINTS);

glVertex3f(-1.0f,0.0f, 0.0f);

glVertex3f(0.0f,0.0f, 0.0f);

glVertex3f(1.0f,0.0f, 0.0f);

glEnd();

}

What this code does is sets the colour (White) for our points and then renders 3 GL_POINTS. It will

render a white point at every vertex submitted between glBegin(GL_POINTS) and glEnd(). If you

compile and run now you should see 3 white dots rendered in a line about 1/3 from the bottom of

your screen.

You should see something like the screenshot above. This is just to confirm that we have everything

setup correctly and that we are ready to start creating our Particle System.

Page 6: OpenGL - Particle System Tutorial - Blending - Point Sprites

Creating the Particle System What we are going to do is define a particle using a structure. Each particle will contain information

regarding its position, movement, colour, etc. etc. We will then create an array of particles that we

can loop through to initialise, adjust and render our particles.

Setting a Constant for MAX_PARTICLES We can use a constant to set the maximum number of particles to render in our system. We could

have used an (int) variable but using a constant has the advantage of being able to be used to define

the size of our Particle array as well as to be used in our loop routines. Insert the following line at

the very top of you main.cpp

#define MAX_PARTICLES 100

This will give us 100 particles to play with initially which should be plenty.

Defining our Particle Structure We now need to define our Particle structure. The following code needs to be placed at the top of

of your main.cpp before you WinMain() function. Here is the structure code:

struct PARTICLE {

float X,Y,Z; // Current position

float sX,sY,sZ; // Current Speed/Movement

float tX,tY,tZ; // Target Speed/Movement

float R,B,G; // Particle Colour

bool Active; // Is particle Active

int Age; // Age of the particle

int MaxAge; // Maximum Age before particle dies

int BounceCount;

} Particles[MAX_PARTICLES];

As you can see, each Particle has quite a few attributes assigned to it. I think it is worth taking some

time to explain what each set of attributes is for and how it will be implemented in our particle

engine. I will also explain the math we are going to use to control the movement of the particles.

Float X,Y,Z

The X,Y,Z float values will hold the position of our particle. We will change these values each frame

to move the particles.

Float sX, sY, sZ, tX, tY, tZ

The sX,sY,sZ values will hold the current speed along the corresponding axis for the Particle. The tX,

tY, tZ will hold the target speed of each particle. This is an interesting way of simulating the effect of

gravity and motion without consuming too much CPU time. What we do is set a static target speed

for the particles. We will use a target speed of (0.0f, -1.0f, 0.0f) which equates to straight down at a

speed of -1.0f per frame. This will be the same for all particles.

To simulate the effect of gravity we then assign a current speed to each particle in a direction of up.

We will generate a random value for sX, sY and sZ when we activate the particle. What we will do

with these values is, in each frame, we will move the current speed vector towards the target speed

Page 7: OpenGL - Particle System Tutorial - Blending - Point Sprites

vector. We will move it by a percentage which will effectively steer the particle towards its desired

target speed/direction. If it is moving up it will slow down before it starts falling and will fall faster

for each frame. Also, the left/right motion will slowly reduce to nearly zero along X and Z. I will

explain more when we get to coding the AdjustParticle() Routine.

Float R,G,B

These values will hold the colour of the particle. This will be useful if we want to rotate the colours

in our Particle System.

Bool Active

This will be set to true if the particle is active. We will only adjust and render active particles. Also,

each frame we will activate one particle if there are any that are inactive up to the MAX_PARTICLES

value.

Int Age and MaxAge

We will assign each particle a maximum age which will be the maximum number of frames that the

particle will be rendered for before it is set to inactive. Each frame we will add 1 to the age until it

reaches MaxAge and then set to inactive.

Int BounceCount

During adjustment of the particle we will check to see if the Y position has dropped below zero. If it

has then we will reverse the sY value to send it back up which will create a bouncing effect. Also,

because of the interaction between sY and tY each bounce will be slightly lower than the next

creating an effective bouncing simulation that can be quite realistic with the right values. We will

use the BounceCount to store a count of times each particle has bounced. This will allow us to set a

particle to inactive if it bounces more than, say, three times. This will avoid having active particles

sitting motionless.

Particles[MAX_PARTICLES];

This line at the end defines an array of PARTICLE structures.

Initialising the Particles Once we have defined the particle store we can then look at activating it in our code. We do this in

our InitParticles() function. It should look like this:

void InitParticles(){

int p;

srand((int)time(NULL));

for(p=0; p<MAX_PARTICLES; p++){

Particles[p].Active = false;

Particles[p].tX = 0.0f;

Particles[p].tY = -0.1f;

Particles[p].tZ = 0.0f;

}

}

Page 8: OpenGL - Particle System Tutorial - Blending - Point Sprites

What we are doing here is simply looping through all of our particles and setting the target speed

values that we want to use. We are also setting all of them to inactive as they will be activate one

each frame. This gives us a smoother start to our rendering rather than starting with 100 particles

onscreen.

Also, notice that we are taking the opportunity to seed the rand() function so that we can use it later

to generate random valued later on. As we are seeding by the system time we need to include

time.h at the top of our main.cpp file.

#include <time.h>

Activating the Particles The particles are activated using the ActivateParticles() routine. It should look like this:

void ActivateParticles(){

int p;

for(p=0; p<MAX_PARTICLES; p++){

if(!Particles[p].Active){

// Start the particle at 0,0,0 origin

Particles[p].X = 0.0f;

Particles[p].Y = 0.0f;

Particles[p].Z = 0.0f;

// The following lines set a random speed value

Particles[p].sX = (((float)((rand() % 100) + 1)) /

1000.0f) - 0.05f;

Particles[p].sY = (((float)((rand() % 100) + 50)) /

500.0f);

Particles[p].sZ = (((float)((rand() % 100) + 1)) /

1000.0f) - 0.05f;

// We also activate the particle

Particles[p].Active = true;

// Set it's Age to zero

Particles[p].Age = 0;

// We also assign a max age to the particles

Particles[p].MaxAge = MAX_PARTICLE_AGE;

// We Also reset the bouncecount to zero

Particles[p].BounceCount = 0;

return;

}

}

}

The comments state what we are doing with each statement. The values set for the current speed

are random float values which are divided down from integers to get a range from 0.00 to 0.10 and

then are adjusted by -0.05f to give us values for sX and sZ of between -0.05 and 0.05. I have

Page 9: OpenGL - Particle System Tutorial - Blending - Point Sprites

tweaked the sY values to get a good height of our particle system. You can play with these numbers

to change the effect you get.

An additional not regarding this routing is the placement of the return; statement. Putting it inside

the if() statement means that only 1 particle will be activated per frame because the function will

exit once this has been done.

Adjusting the Particles Adjusting the particles is done in the AdjustParticles() routine. It should look like this:

void AdjustParticles(){

int p;

for(p=0; p<MAX_PARTICLES; p++){

// We move the speed towards the target speed by 1/20 (5%)

Particles[p].sX+= (Particles[p].tX - Particles[p].sX) / 20.0f;

Particles[p].sY+= (Particles[p].tY - Particles[p].sY) / 20.0f;

Particles[p].sZ+= (Particles[p].tZ - Particles[p].sZ) / 20.0f;

// Then we adjust the position of

// the particle by the new speed

Particles[p].X+= Particles[p].sX;

Particles[p].Y+= Particles[p].sY;

Particles[p].Z+= Particles[p].sZ;

// Now for the bounce code.

if(Particles[p].Y < 0.0f){

Particles[p].Y = 0.0f;

Particles[p].sY = -Particles[p].sY;

Particles[p].BounceCount++;

if(Particles[p].BounceCount > MAX_BOUNCE_COUNT){

Particles[p].Active = false;

}

}

// And finally the age check

Particles[p].Age++;

if(Particles[p].Age > Particles[p].MaxAge){

Particles[p].Active = false;

}

}

}

Here we are adjusting the particle settings according to the comments in the code. Note the check

of MAX_BOUNCE_COUNT which we need to set as a constant. I have used a value of 5 in my

example.

#define MAX_BOUNCE_COUNT 5

Page 10: OpenGL - Particle System Tutorial - Blending - Point Sprites

For each of the speed values sX, sY, sZ we are taking the difference between the target and the

source speeds and dividing it by 20 before adding it to the current speed.

Rendering the Particles Initially we are going to use GL_POINTS for our particles. The RenderParticles() function should now

look like this:

void RenderParticles(){

int p;

glBegin(GL_POINTS);

for(p=0; p<MAX_PARTICLES; p++){

if(Particles[p].Active){

glColor4f(1.0f, 1.0f, 1.0f, 0.5f);

glVertex3f(Particles[p].X,

Particles[p].Y,

Particles[p].Z);

}

}

glEnd();

}

We have already translated to the origin of our Particle System so, in the RenderParticles() function

we first instruct OpenGL that every vertex until glEnd() should be rendered as a point. We then loop

through our particle array and issue a glVertex3f() call for each active particle. Then, when we are

done we issue glEnd() and we are done. Compile and run the code. You should see a cool looking

fountain of points rendered on the screen like this.

Page 11: OpenGL - Particle System Tutorial - Blending - Point Sprites

Changing Colours OK. What we have now is OK and it is a functioning Particle System. Now let’s take a look at how

we can improve the effect we are getting. The first thing we can do is have the colours rotate. To do

this we can use the R,G and B values for our particles. Before we can start rotating colours we need

to setup some additional variables. Add the following code at the top of your main.cpp file:

float R = 0.8f;

float G = 0.2f;

float B = 0.0f;

float cR = 0.001f;

float cG = 0.002f;

float cB = 0.003f;

We are defining global variables for Red, Green and Blue which is the colour we will be setting for

each particle when we activated it. I have assigned some values picked at random. Then we are

defining change variables cR, cG and cB. These will be added to R,G and B each time we activate a

particle so that the colour changes. The reason these are small values to to make the colour change

slowly.

The next code we need to add is in our ActivateParticles() function. It should now look like this:

void ActivateParticles(){

int p;

for(p=0; p<MAX_PARTICLES; p++){

if(!Particles[p].Active){

// Start the particle at 0,0,0 origin

Particles[p].X = 0.0f;

Particles[p].Y = 0.0f;

Particles[p].Z = 0.0f;

// The following lines set a random speed value

Particles[p].sX = (((float)((rand() % 100) + 1)) /

1000.0f) - 0.05f;

Particles[p].sY = (((float)((rand() % 100) + 50)) /

500.0f);

Particles[p].sZ = (((float)((rand() % 100) + 1)) /

1000.0f) - 0.05f;

// We also activate the particle

Particles[p].Active = true;

// Set it's Age to zero

Particles[p].Age = 0;

// We also assign a max age to the particles

Particles[p].MaxAge = MAX_PARTICLE_AGE;

// We Also reset the bouncecount to zero

Particles[p].BounceCount = 0;

Page 12: OpenGL - Particle System Tutorial - Blending - Point Sprites

Particles[p].R = R;

Particles[p].G = G;

Particles[p].B = B;

R+=cR;

G+=cG;

B+=cB;

if(R>1.0f){R=1.0f; cR=-cR;}

if(R<0.0f){R=0.0f; cR=-cR;}

if(G>1.0f){G=1.0f; cG=-cG;}

if(G<0.0f){G=0.0f; cG=-cG;}

if(B>1.0f){B=1.0f; cB=-cB;}

if(B<0.0f){B=0.0f; cB=-cB;}

return;

}

}

}

What we have added is code to set the particle colour to our R,G, and B variables. Then we add the

colour change variable to the colours so that the next particle activated will have a slightly different

colour.

Then, the last 6 lines simply check if the R,G and B values are greater than 1.0f or less than 0.0f and,

if they are, the change variables are reversed to move in the opposite direction.

Now all we need to do is to use the Particle colour values in our RenderParticles() function. Change

the glColor4f() call from from all 1.0f values to read the following:

glColor4f(Particles[p].R, Particles[p].G, Particles[p].B, 0.5f);

Now we can compile again and run the code. You should now see the colour of the particles slowly

changing as it runs. Looks a little better but we can still improve it. Let’s move on.

Page 13: OpenGL - Particle System Tutorial - Blending - Point Sprites

Using Textured Quads instead of Points OK. Now that we have a particle system that works we need to look at using textures for our

particles instead of points. This will significantly improve the look of our particle system. There are

a few things we need to do before we can get this working. Before we get started I want to explain

what we are going to with these textures.

We will load the textures and then for each particle we will render a quad (square) that faces the

camera. On that quad we will render the texture we have loaded.

Loading the Bitmap Texture We need to add the following function to our code:

bool LoadBitmapTexture(char * FileName, GLuint &texid){

HBITMAP hBMP; // Handle Of The Bitmap

BITMAP BMP; // Bitmap Structure

glGenTextures(1, &texid); // Create The Texture

hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL),

FileName,

IMAGE_BITMAP, 0, 0,

LR_CREATEDIBSECTION | LR_LOADFROMFILE

);

if (!hBMP) // Does The Bitmap Exist?

return FALSE; // If Not Return False

GetObject(hBMP, sizeof(BMP), &BMP); // Get The Object

// hBMP: Handle To Graphics Object

// sizeof(BMP): Size Of Buffer For Object Information

// &BMP: Buffer For Object Information

glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

// Pixel Storage Mode (Word Alignment / 4 Bytes)

// Typical Texture Generation Using Data From The Bitmap

glBindTexture(GL_TEXTURE_2D, texid);// Bind To The Texture ID

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,

GL_LINEAR); // Linear Min Filter

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,

GL_LINEAR); // Linear Mag Filter

glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth, BMP.bmHeight,

0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);

DeleteObject(hBMP); // Delete The Object

return TRUE; // Loading Was Successful

}

This function will load a bitmap file and store it as a texture we can use when rendering. For the

purpose of this tutorial I am not going to go into the ins and outs of each line of code. I may write a

tutorial on this at some point in the future but for now, if you want more information on this then

checkout NeHe.GameDev.net which is a fantastic site for OpenGL tutorials.

Page 14: OpenGL - Particle System Tutorial - Blending - Point Sprites

Once this function has been added you will then need to call it in your InitParticles() function.

Before you do that though you will need to add the function declaration at the top of your main.cpp

and you will have to define a GLuint value to hold the GL Texture ID that you load. Add the following

lined to the top of your code:

bool LoadBitmapTexture(char * FileName, GLuint &texid);

GLuint txParticle;

What we are going to do now is call LoadBitmapTexture() from our InitParticles() function which will

store the loaded TextureID into the txParticle GLuint variable.

This is the texture we will be loading:

This was created with the GiMP. It has to be 24bit colour bitmap image. The effect in the image is

white but, when we render, the colour specified for the particle will be blended with the image to

allow the colours to continue to change.

Add the following line to your InitParticles() routine:

LoadBitmapTexture("./Particle.bmp", txParticle);

This will now have loaded the texture and it should be ready to use. We can now update our

rendering routine to make use of the texture. You need to place a copy of Particle.bmp in your

Debug folder so that it can be found by the application when it runs.

Rendering Quads as Points The first thing we need to do is setup a variable to determine the size of our point. Add the

following at the top of your main.cpp file:

float Size = 0.1f;

This is the size of the points we will render. Actually, in this example it will be the distance between

the centre of the quad and each edge.

What we will do is enable textures (GL_TEXTURE_2D) and bind our texture. Then we will need to

enable blending. We don’t want each of our particles to have a black square around it. We will use

a glBlendFunc() with GL_SRC_COLOR, GL_ONE as the parameters. Again, a full description of the

glBlendFunc() function is outside the scope of this tutorial but basically, these attributes mean that

we will mix the source (IMAGE) colour with the destination background.

Page 15: OpenGL - Particle System Tutorial - Blending - Point Sprites

We also need to disable GL_DEPTH_TEST so that the engine will not check if there is another quad in

front of it. If we do not do this then the ordering of the quads will lead to some of the quads being

rendered with black squares around them.

We now need to update our RenderParticles() function. It should look like this:

void RenderParticles(){

int p;

// Enable textures and bind our particle texture

glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, txParticle);

// Disable Depth testing.

glDisable(GL_DEPTH_TEST);

// Enable blending

glEnable(GL_BLEND);

glBlendFunc(GL_SRC_COLOR,GL_ONE);

for(p=0; p<MAX_PARTICLES; p++){

if(Particles[p].Active){

glColor4f(Particles[p].R,

Particles[p].G,

Particles[p].B, 1.0f);

glPushMatrix();

glTranslatef(Particles[p].X,

Particles[p].Y,

Particles[p].Z);

glBegin(GL_QUADS);

glNormal3f(0.0f, 0.0f, 1.0f);

glTexCoord2f(0.0f, 0.0f);

glVertex3f(-Size, -Size, 0.0f);

glTexCoord2f(1.0f, 0.0f);

glVertex3f(Size, -Size, 0.0f);

glTexCoord2f(1.0f, 1.0f);

glVertex3f(Size, Size, 0.0f);

glTexCoord2f(0.0f, 1.0f);

glVertex3f(-Size, Size, 0.0f);

glEnd();

glPopMatrix();

}

}

glEnable(GL_DEPTH_TEST);

}

Page 16: OpenGL - Particle System Tutorial - Blending - Point Sprites

For each particle we are going to render a quad. There are a few steps to undertake to do this. First

we are going to push the translation matrix to the matrix stack. This is because we are going to need

to translate to the centre of each particle and we will need to be able to return the matrix back to its

original state ready to render the next particle.

We then translate to the centre point (X,Y,Z) of the particle. Once there we call glBegin(GL_QUADS)

which instructs OpenGL to draw a QUAD for each set of 4 vertices entered until the call to glEnd().

We are setting a glNormal3f() which points away from the surface of the quad. (Take a look in

snippets on www.fullonsoftware.co.uk for a tutorial on calculating normals). We have not enabled

lighting but the call is there if we do. We then set the texture coordinates and vertex for each corner

of our quad.

We have to issue the vertices in anticlockwise order. In this case we start with the bottom left and

work our way round. We use –Size and Size for our values. Z stays static at 0.0f.

At the end we re-enable GL_DEPTH_TEST as it is likely that we will need this on later.

Now build and run your code. I think that is a significant improvement on using GL_POINTS. Also,

the results of the blending and removing the depth testing are very effective. It should look

something like this:

Page 17: OpenGL - Particle System Tutorial - Blending - Point Sprites

Adding a plane to bounce off I think we should now add a plane/surface for the particles to bounce off. We can do this by

rendering another textured quad. We will centre it at the same point as our particle system but this

one we will lay flat at a height of zero.

You will need another texture for this. I like this one because of the effect it gives:

Save a copy of it as a 256x256 24bit Bitmap file called Plane.bmp in your debug folder and then add

the following line in your InitParticles() functions:

LoadBitmapTexture("./Plane.bmp", txPlane);

We can then add a few lines of code to your DrawGLScene() function to render the plane. You need

to add the following in this function. It needs to be after your initial translation to the point of the

particle system but before the call to RenderParticles().

glEnable(GL_BLEND);

glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);

glColor4f(0.0f, 0.2f, 0.2f, 0.5f);

glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, txPlane);

glBegin(GL_QUADS);

glNormal3f(0.0f, 1.0f, 0.0f);

glTexCoord2f(0.0f, 0.0f);

glVertex3f(-10.0f, 0.0f, 10.0f);

glTexCoord2f(1.0f, 0.0f);

glVertex3f( 10.0f, 0.0f, 10.0f);

glTexCoord2f(1.0f, 1.0f);

glVertex3f( 10.0f, 0.0f, -10.0f);

glTexCoord2f(0.0f, 1.0f);

glVertex3f(-10.0f, 0.0f, -10.0f);

glEnd();

This will enable textures, blending and set a colour for the texture. It will then render a quad from

that centre point.

Page 18: OpenGL - Particle System Tutorial - Blending - Point Sprites

The scene should now look like this.

You can adjust the colour and blend settings to change the appearance of the base but I like the way

it looks with these settings. It isn’t too bright and that is good as you will see in the next section.

Page 19: OpenGL - Particle System Tutorial - Blending - Point Sprites

Adding Reflection of the particle system I was thinking it would be a good effect to add a reflection of our particle system in the plane we

have just created. However, you cannot simply enable reflections on surfaces. What we actually do

is render our entire particle system below the plane. We then draw the plane with blending over

the top to give the appearance of reflection. Finally we render our actual system on the top.

Add the following code to your DrawGLScene function immediately after your initial translation and

before the code to render the plane.

glPushMatrix();

glScalef(1.0f, -1.0f, 1.0f);

RenderParticles();

glPopMatrix();

What this code does is push the matix so that we can set it back afterwards. Then it issued glScale()

with -1.0f for the Y value. All subsequent vertex calls and translations etc, will be multiplied by the

values of glScale(). By setting 1.0f for X and Z we are leaving them unchanged. Then the -1.0f will

invert all of the Y coordinates for our particles. Hey presto, instant reflection. It should look

something like this:

Page 20: OpenGL - Particle System Tutorial - Blending - Point Sprites

All Done So that is it. A simple OpenGL Particle System that uses textures to create pretty cool visual effect.

You can try messing with the parameters for colours and blending, changing the images and rotating

the whole scene to generating different effects.

As far as point sprites are concerned, I think what we have implemented in this tutorial is a method

of point billboarding that does not require the use of specific extensions. There are specific point

sprite extensions for Nvidia devices for example but I think using textured quads as our points is very

effective.

Also, note that this is a simple scene that is static. If you want to use this style of particle system in

your own projects then it is likely that your scene will not be static. In these cases you will need to

implement some code to make sure that each quad is rendered facing the camera. If you don’t then

your points will distort as your scene moves and rotates.

Useful references http://NeHe.GameDev.net The NeHe OpenGL Tutorials are second to none and a fantastic place to get started with OpenGL. http://www.fullonsoftware.co.uk This is my website. There is a snippets section with code samples and tutorials and stuff. http://www.gimp.org Website of the GNU Image Manipulation Project (GIMP). This program is free and was used to generate the images for textures in this example. mailto:[email protected] This is my email address. Let me know if you have any questions regarding the contents of this tutorial or would like to suggest a subject for a future tutorial. Also, please let me know if you find any errors so that I can correct them. Also, I would be interested to know if the code in this tutorial is used in your project. I would be great to see it in action. Thanks for reading! Richard Sabbarton