proper rendering for particles?

Ok. I’ve been working on a little demo to develop a good frame work for a particle system that I’ll eventually use in a 3D engine. I have all the physics down and the particles react as they should (gravity, velocity, etc…) My only problem is rendering the little suckers. I use a small 16x16 texture for this particular example. It’s an 8-bit grayscale targa that I expand to 24-bits RGB before uploading it to the graphics card. I start the scene off with the particles using blend mode GL_SRC_ALPHA, GL_ONE and a depth func of GL_ALWAYS, then I draw the rest of the scene. I know you are thinking this is wrong. I know it is. The particles don’t blend with the rest of the scene, only with themselves. My problem is, when I draw the particles last, I can’t very well disable depth checking because that will cause particles behind solid objects to become visible. This is unacceptable. I don’t wanna check each particle against every poly in the scene because that would take FAR too long (1,000+ particles and 4,000+ triangles in this particular scene) Can anyone give me some advice on how to pull this off? Tutorials? Documentation of any type? Sample code? Thanks.

For transparent polygons, such as your particles, first render the opaque scene. Then disable depth writes, leave depth testing enabled, depth sort the transparent polygons, and draw them from far to near. Usually, a Quicksort is sufficient for sorting the transparent polygons.

[This message has been edited by DFrey (edited 07-11-2000).]

First of all, thanks for the fast reply! That worked like a charm. I knew it’d be simple like that. The depth sorting I didn’t bother with because the amout of particles and the randomness of their Z coordinates is so great, you don’t really notice. In this particular case anyway.

If you do as DFrey says, and sets a proper blendmode, you don’t have to depthsort them, even if they are close to each other. My particle engine is working like that, and I didn’t see any difference when I implemented a depthsort (except perforanceloss ).

For sparks and other lightemitting particles, you might want to use GL_ONE and GL_ONE. For smoke and other “dark” particles, you use another blend mode, tell me if you want to know what and i post it, I don’t have access to the code at the moment.

I’m interested, too.

Uh, yes you do have to depth sort Bob. If you have a scene with multiple transparent surfaces and transparent particles, you will clearly see an error in the rendering order when particles that are far away are rendered on top of a transparent surface that is nearer the viewer (or vice versa), a paradox appears in that their size says they are far away, but the color says they are near. And believe me, I’ve seen this ugly paradox with just two particles that where attached to a larger model. In my graphics engine, all transparent polygons are treated equally, be they from fixed surfaces, or billboarded sprites. And the depth sorting removes all sign of paradox. And it is not that big of a performance hit. You just have to decide what you want. Accuracy in rendering, or a few more frames per second. I’ll take the accuracy over frames per second any day.

[This message has been edited by DFrey (edited 07-12-2000).]

DFrey, it depends on the blend mode. For the usual (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) you’re right, you have to depth-sort or it’s going to suck.

But for “light-emitting” particles like sparks you’ll often want to use an additive blendfunc like (GL_SRC_ALPHA,GL_ONE). In this case you DON’T need to depth-sort, because you’re just doing addition and addition is commutative.

[update after rereading - I think Bob and I are talking about an optimizable case where ALL transparent primitives are using an additive blendmode, or where all such primitives occupy volumes which can be depth-sorted as a single entity with respect to with other transparent primitive. DFrey is talking about a completely general engine which assumes that transparent primitives are all mixed up and have arbitrary blend modes. As usual, horses for courses.]

[This message has been edited by MikeC (edited 07-12-2000).]

Bob: I use GL_SRC_ALPHA,GL_ONE due to the fact the these ‘sparks’ have to appear to fade or burn out, as their life increases. GL_ONE,GL_ONE does allow for the sparks to be transparent, but I can’t get this same effect. I use the same mode for smoke.

Ah! Now I see, MikeC! But what do you do if you have a scene that mixes those types of particles? Will not you then need to sort all of them? Or should the emissive particles just always be drawn last?

[hehe, yea, that’s really cool MikeC, you hit the target’s bullseye. And yes, I was worried about switching blending modes and binding new textures for potentially every polygon, but that has so far never happened. It is a worst case scenario which could occur however, so I just need to be a little careful in the design of the scene and not take too much liberty in using multiple textures. Oh and many of my particle textures are subimages of a larger texture so that helps with the binding issues.]

[This message has been edited by DFrey (edited 07-12-2000).]

DFrey, see my edited previous post. Answering questions before reading them… cool huh? :slight_smile:

Actually I’d worry about the generalized approach where everything is depth-sorted together - if you’re potentially switching blend modes and possibly binding different textures for EACH AND EVERY PARTICLE, performance is going to drop through the floor…

It occurs to me that the best way to improve performance when depth sorting primitives with different material properties could be to form groups of non-intersecting primitives. The elements in each group could be sub-grouped by material for trasversal.

Assuming that the number of materials isn’t great this should reduce state changes by a considerable factor.

I think the concern here may become the complexity of the grouping and sorting algorythm…

Anyone have any ideas about how to approach such an algorythm?

When you have sparks or other light emitters/grabbers like that, you should really draw in three passes:

  1. Opaque
  2. Transparent with opaque fields (overwriting rather than additive or subtractive drawing) (z sorted)
  3. additive/subtractive (sparks, smoke) which are not depth dependent (not z sorted)

Unfortunately, you will have a problem if the sparks are supposed to fly behind some polygon which is partly transparent – they’d actually “shine through”. Perhaps you can figure out some alpha test or stencil test mechanism which will fix this.

Too bad two thirds of the cards out there don’t do those tests in hardware :frowning:

Ok, just wanted to say: don’t forget that you can use the so called fourth colorcomponent, alpha, to create fading effects too. By decreasing the alphavalue, then can fade away.
And by using either GL_ALPHA or GL_LUMINANCE textures with a proper blendingmode, you can come up with pretty neat particle effects, and you just have to render them as they appear in the list/array/whatever. And even smoke-like particles (where colors just don’t add together) is possible.

My tip is to play around with both blendmodes AND internal textureformats. Same effects can occur with several different settings, but some of them may be faster (like if you don’t have to depthsort ).