gpu particle engine

Started by
10 comments, last by jeffjets 18 years, 4 months ago
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.
Advertisement
Have you read this? Building a Million-Particle System
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Quote:Original post by JohnBolton
Have you read this? Building a Million-Particle System


Holy... million? And I thought I was doing fine with 100k. Or 50k, seeing how point sprites were completely broken on ATI and I had to create a really sick way to do it in a shader.
f@dzhttp://festini.device-zero.de


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


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.
Create a render target texture and render to that?
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.
So you could create a render texture 512x512, set it as the render target, then draw a 512x512 quad into it having selected your pixel/fragment shader first?
I guess that would work, just be a waste of the extra memory.

This topic is closed to new replies.

Advertisement