You are on page 1of 20

www.fullonsoftware.co.

uk

OpenGL Particle Systems


Using PointSprites, Textures and Blending in Microsoft Visual C++ 2008 Express Edition
Richard Sabbarton

08

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

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.

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 lets start by simply rendering a few points on screen. Well 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 lets not run before we can walk. Lets add a few lines to our RenderParticles() functions so that it looks like this:

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.

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; float sX,sY,sZ; float tX,tY,tZ; float R,B,G; bool Active; int Age; int MaxAge; 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 // // // // // // // Current position Current Speed/Movement Target Speed/Movement Particle Colour Is particle Active Age of the particle Maximum Age before particle dies

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; } }

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

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 Particles[p].sX+= (Particles[p].tX - Particles[p].sX) Particles[p].sY+= (Particles[p].tY - Particles[p].sY) Particles[p].sZ+= (Particles[p].tZ - Particles[p].sZ) // 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 (5%) / 20.0f; / 20.0f; / 20.0f;

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.

Changing Colours
OK. What we have now is OK and it is a functioning Particle System. Now lets 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 float float float float float R = 0.8f; G = 0.2f; B = 0.0f; cR = 0.001f; cG = 0.002f; 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 Particles[p].sX = (((float)((rand() 1000.0f) Particles[p].sY = (((float)((rand() 500.0f); Particles[p].sZ = (((float)((rand() 1000.0f) speed value % 100) + 1)) / - 0.05f; % 100) + 50)) / % 100) + 1)) / - 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;

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. Lets move on.

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); return TRUE; } 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. // Delete The Object // Loading Was Successful

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 dont 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.

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); }

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:

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.

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 isnt too bright and that is good as you will see in the next section.

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:

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 dont 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:richard.sabbarton@gmail.com 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

You might also like