PDA

View Full Version : Particle blending mess



bill2727
05-23-2003, 08:52 PM
So I whipped up a pretty little particle engine, but ran into a rather embarassing roadblock when trying to render the system on anything but a black background. Problem is by blending the source pixels of the particles with the destination, the original color of the effect gets completely washed out. For example if I try my fire effect which looks perfect on a black background, its bright freaking purple against a blue background! So it seems to be what is needed is a way to blend particles with each other and not with the environment (or at least not so much), but still making sure they only blend the circular "particle" shape on the quad... and the whole quads don't blend together!
I would assume this problem has been encountered many times, but I couldn't find any tutorial or paper that mentioned it.
I'd appreciate any suggestions.
Terrence

Mezz
05-24-2003, 02:19 AM
Hmm... are you using a glBlendFunc() with GL_ONE and GL_SRC_COLOR in it somewhere?
Generally, to maintain the colour of the particles while ensuring you don't get the black around the texture edges, you'll want to use the alpha channel of the texture and set the blendfunc to something like

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Remember to upload your new RGBA texture with the correct parameters to glTexImage2D() or you'll get some weird results http://192.48.159.181/discussion_boards/ubb/smile.gif

-Mezz

bill2727
05-24-2003, 09:30 AM
Could you elaborate on that a bit? I've tried several different blending modes, but the one that works perfectly on a black background is:
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
So I have a particle StartColor and EndColor, and StartAlpha, and EndAlpha. On the black background they fade out and change colors just as they should.. but as I said on a different color background they blend very undesirably.
So are you saying I actually need an alpha channel on my texture rather than a 3 channel texture with an alpha color parameter? I just don't understand how that'll help..

jwatte
05-24-2003, 09:39 AM
What blend you use is of course dependent on what effect you want. You might want to mock up a few backgrounds and a few particles in Photoshop layers and play with the different layer composite modes, which are very similar to framebuffer blend modes, to figure out which one you want.

The trick in particle systems (once you get them to run fast :-) is often in preparing correct source art, which is trickier than it first appears.

For fire, you often want GL_ONE, GL_ONE. This means that the source color is added to the destination color. This means that the fire is emitting light, which is pretty much what you want (right?). Remember that colors are very seldom pure; you probably want your blue sky to have a fair bit of green and a reasonable amount of red in it; similarly, you want your red fire to have a little bit of green (to tint it orange) and maybe some blue just to get the gray level up. The color could actually fade to red towards the fringes of the particles.

If you're using GL_ONE for the src mask, then your particles should be black where you want no color added, and bright where you want lots of effect (towards the center).

If you want to get fancier, you may wish to use GL_ONE, GL_ONE_MINUS_SRC_ALPHA for blend modes. This lets you vary the source texture between translucency/opacity (high alpha) and additive (low/zero alpha). This is great for adding soot/smoke around the edges of a fiery particle; you'll have zero alpha in the bright middle and black edge, but fade it in to about 1/2 alpha inbetween, where you'll draw a ruddy gray mixed with black for soot/smoke.

bill2727
05-24-2003, 12:40 PM
I've messed with this alot, and to sum up what I want to see, but have never gotten is:
1)Particle quads only displaying the particle in the middle of it, which is not just a single white dot but a white dot blended into gray on its borders.

2)Particles need to blend with each other (so they get brighter, as fire or something should) but either minimally or not at all with the background (because that completely destroys the color of the original effect).

3)Particles need to be occluded by scenery, i.e. they can't COMPLETELY ignore the depth test or they'll be drawn if they're behind walls.

jwatte: I've tried using GL_ONE, GL_ONE, but that doesn't satisfy 2. Maybe I'm not communicating this well, but if there is a blue(not even pure blue, just a blue tinted) wall and I use my fire effect in front of it, the fire is bright purple! That is just a mockery of reality, and would look ridiculous if I used it in my project.

jwatte
05-24-2003, 08:07 PM
There is an inherent contradiction in 2). 3) is not much of a problem.

One alternative would be to render into a pbuffer with destination alpha, and then CopyTexSubImage into a texture and render the texture on a single quad. If you need volume, then you have to do something depth-sprite-like which may require a ARB_fragment_program shader.

You could perhaps do something with destination alpha, where the destination alpha is written by the source particle, and blend mode uses destination alpha. Although you still won't get exactly the properties you expect out of 2).

Korval
05-24-2003, 08:39 PM
One alternative would be to render into a pbuffer with destination alpha, and then CopyTexSubImage into a texture and render the texture on a single quad.

I'm not certain, but isn't the whole point of pbuffers to have the ability to use them as the source directly for a texture? Thus, unless you happen to be using nVidia hardware, removing the need for the texture copy?

bill2727
05-24-2003, 09:07 PM
jwatte: You'll have to explain to me the "inherent contradiction" in 2. When I see an explosion it doesn't matter what's behind it, the effect is ALWAYS red and orange. I've seen it done, and I know it can be done. The problem is of course real explosions don't use a blending function to determine their color :-(
So for an effect independent of background, like an explosion, I would like it to look exactly like my explosion on a black background (except perhaps on the fringes, and the smoke, both of which WOULD blend with the background). I don't know what's so impossibly hard about that request..

Roderic (Ingenu)
05-25-2003, 12:34 AM
Src.Color * Src.Alpha + Dest.Color * 1, you tend to reach saturation pretty fast.

Tried the standard blending equation with high Alpha values ?
Src.Color * Src.Alpha + Dest.Color * ( 1 - Src.Alpha )
You'll reach Saturation slower.

With the above equation you'll get mostly Red no matter the bckgrd color as you wanted pretty fast.
example on a sample pixel:
(64,0,0) * 0.75 + (0,0,255) * 0.25 = (48,0,64)
(64,0,0) * 0.75 + (48,0,64) * 0.25 = (76,0,14)
(64,0,0) * 0.75 + (76,0,14) * 0.25 = (83,0,4)


Note that your particle is most likely not uniformely alpha, but that its center have a higher alpha (maybe even 1) while its borders should be around 0.

jwatte
05-25-2003, 07:08 PM
Ingenu, that's exactly what Mess recommended in the first post. That implement "blending" as in "compositing". If that's what you want to do: blend one image on top of another (rather than add light, like most real flames would do) then that's the right solution.

Btw: a red flame against a blue sky DOES look purple in real life.

bill2727
05-25-2003, 07:58 PM
jwatte:
Maybe a tiny little candle is tinted with the sky color (NOT purple) but thankfully I'm not in the candle simulator business. Any appreciable explosion or fire is blocks out the background.
And to adress your comment about Mezz's first post, I actually did that, that was one of the things I tried. Using SRC_ALPHA, ONE_MINUS_SRC_ALPHA and an RGBA texture, I can get particles to be round, and not to absorb the background color. However the blending with each other looks absolutely TERRIBLE relative to SRC_ALPHA, ONE.. you get such little color variance, and no white highlights

Mezz
05-25-2003, 11:30 PM
OK.

Well, I think the "inherent contradiction" is is that you want them to blend with other particles, but not with the background - you can't separate the two since they're already in the colour buffer.

I'd assume this would be why jwatte suggested rendering your particles to a pbuffer, however, I don't know how you would resolve depth testing in this case. You might have to render the scene (well, depths only) to the pbuffer first.

It would be nice if you could do something with the stencil buffer like "only blend where there are pixels in there" but I don't think it's possible.

-Mezz

PS: jwatte it's z http://192.48.159.181/discussion_boards/ubb/wink.gif

bill2727
05-25-2003, 11:45 PM
Wow, I'm really suprised its so hard to do. It seems like countless 3D games out now have particle effects that do exactly as I describe. It just seems there should be some way to flag the background (or draw things in the right order) so that the particles don't have to deal with it.

JustHanging
05-26-2003, 01:28 AM
One thing you could do is to first mask out the background so it's black under the particles and then draw the particles with additive blending. You can store the "opacity" in the particle's alpha channel, after that it's

First pass: GL_ZERO, GL_ONE_MINUS_SRC_ALPHA
Second pass: GL_ONE, GL_ONE

-Ilkka

Mezz
05-26-2003, 02:19 AM
Hmm...
what JustHanging said seems like it might be a sound plan, but it does mean rendering your particles twice (although arguably the second pass could be done without depth writing/testing).

-Mezz

Ysaneya
05-26-2003, 05:45 AM
Funny, i answered on his question on gamedev.net and suggested exactly the same thing than JustHanging :)

Y.

bill2727
05-26-2003, 09:38 AM
Yes Ysaneya, its weird how as you said, about half the people seem to understand it even less well than me, and then serendipitously I get what seems to be a valid answer from two places at once! Unfortunately I don't have access to the computer right now, but I'll post screenshots assuming it works.
So use an RGBA texture in MODULATE TexEnv mode, set DepthMask to FALSE, draw all particles once with GL_ZERO, GL_ONE_MINUS_SRC_ALPHA, and then again with GL_ONE, GL_ONE?
Oh and I don't want to get too sentimental considering I don't know if it works yet, but thanks regardless because I really couldn't afford to put off solving this problem any longer.