Sign in to follow this  
jeffjets

gpu particle engine

Recommended Posts

Hello all. I have been messing around with particles for a bit for my game engine and am trying to get something that will work quite well and fast so I can use it along with my other rendering code. I am using OpenGL and the GLSL shading language now to implement this. I started off doing all the computations on the cpu using no gpu stuff at all. Needless to say it was slow and I was not hitting many particles at all before it would kill the FPS. So I messed around a bit and have it working now using point sprites. My code is far from efficient since I didn't start over from scratch to take advantage of everything I have learned so far but I am able to hit around 7-9k particles on the screen with blending and depth testing and stay above 60 FPS. This would be fine if that was all I wanted to do. But I want to use this in my engine and I am afraid that using this on top of the other stuff I have implemented and plan to implement will slow my FPS down to a crawl again. So now I was reading about doing all the particle updates within shaders. I read about using textures to store the data and also read about pbuffers. From what I can grasp out of the few articles I read on them you basically store the particle positions, velocities and colors in either textures or pbuffers and pass them into the shader. Within the shader you do the updating and then you can use the texture/pbuffer after that to render them. You could then either use a shader to render them, or I could use point sprites again. I guess my main question is which way would be the best way to go for this? I haven't done too much with shaders yet so something very complex would be bad =) I was also thinking about using a giant vertex array, would this be faster or is that a bad idea? If you could link to articles with code examples that would be great. Thanks.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster


I recall seeing in articles about PCIX/PCIExpress interfaces (coupled with newer memory buss architectures) on the newer graphic cards & MBos may make Writes and especially Reads from Graphics memory much faster -- thus enhancing uses like this (they even said something to the effect that the boards might not need as much memory as they already have >64M because system memory could be used for a majority of the current graphics memory uses (storing textures....)

Share this post


Link to post
Share on other sites
IMO it's not the number of particles thats interesting, it's the "quality" of the particles that matter.
Having 1 M equally sized particles running in a very limiting test environment isn't that. It reminds me of the demo coding days on the A500, "who can make a dot landscape with the most dots?", I won ofcourse ;)

For reference I made a GPU particle-engine on the X-box (used in MM3), it handled around 10K particles with collisions and spline controlled size, color alpha etc, combined with physical based motion.
Since then I did another engine (effect engine), used in Battlefield MC on the X-box and PS2 (I'm a bit surprised that they actually used it since I left the team over a year before release).
Needless to say the newer version was alot better, not in terms of the number of particles, but rather in appearance, the system had win32 editors that connected to the target platform (PC, PS2 or X-box) and everything was updated in real-time. Particles could be everything from a screen aligned triangle to rotating objects. It supported animated (morphing) objects and textures.
Everything ran on the GPU (Vertex/Pixel shader 1.1 or the VU1).
Besides from particles there were alot of other effects, light effects, sound etc that was all controlled by one system. The artists created all effects using that system. I do not have any performance measurements for the new system.

A particle without collision detection was never touched again by the CPU after it's been spawned. With collision it was only touched when the actually collision happened (doing the response). Typically about 3% of the particles needed CPU involvement every frame (including spawning new particles).

I realize that with shader model 3.0 even more code could go into the shaders, but I'm not sure that it will actually boost the performance that much.
You could probably get a massive speed up moving collision detection to the GPU, but as far as I know there exists no good algorithms that can handle "level size" geometry, for local particle systems it might be a win.

I'd recommend you to just use a vertex shader for your particle system, even vs 1.1 is enough. Use the CPU for collisions.
For physical based particles, it's easy to let the VS move the particles, typically store in vertex:

float time = Time of birth
Vec3 pos = Pos at birth
Vec3 vel = Velocity at birth

Then in the VS calculate:
float Age = CurrentTime - time
Vec3 Pos = pos + vel * Age + Age * Age * Acceleration / 2

It get's slightly more complicated when using air-resistance etc.
Gases could be simulated with zero or negative acceleration etc.
Since the motion of a particle is analytically solvable, you can get the time of collision on the CPU, store it in a queue and when the time of the collision happened, rewrite the time, pos and vel parameters in the VB.

My 2c.


Share this post


Link to post
Share on other sites
That was actually the article I was refering to =) I didn't read it from that page though, that has alot more details. I was reading it from another source that was basically a presentation of this. So would I be better off using say 1 texture for position, 1 texture for velocity and another for holding the color say, or should I create a 3D texture that is like say 512x512x3? I haven't worked with 3D textures much so wasn't sure of the usage of them in a case like this.

How would you go about actually doing it within the shaders? Would I just create a vertex shader and in the shader loop through the entire texture and update it, and then in my main source code just enable the shader and say draw a point so it only calls the shader once? Or should I use a vertex and fragment shader and draw like a 512x512 square so there is an access to the fragment shader for each value of the texture and do the updating in the fragment shader? I guess this part is what worries me more. If I can get this second part sorted out the first part could be done either way I guess, it's just a matter of speed and simplicity.

Share this post


Link to post
Share on other sites
It's not just a matter of rendering to a texture though, it's a matter of rendering to a texture using the hardware(shaders). The whole point of using the texture to store the info was to transfer the data to the shaders to use the hardware for the updating. I was just wondering how to call the shader to do it, because I think you either want to run the vertex shader once and loop through the texture or you want to do 1 call to a fragment shader for each pixel of a texture so you update each particles data.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this