Blending for a Particle System

Started by
9 comments, last by dr4cula 10 years, 4 months ago

Hello,

I'm trying to implement a particle system and the only major issue that seems obvious happens during the blending process of the particles.

Here's the result I'm getting: http://postimg.org/image/w9o9teg6r/

Blend settings:


D3D11_RENDER_TARGET_BLEND_DESC rtbDesc;
rtbDesc.BlendEnable = true;
rtbDesc.SrcBlend = D3D11_BLEND_SRC_ALPHA;
rtbDesc.DestBlend = D3D11_BLEND_DEST_ALPHA;
rtbDesc.BlendOp = D3D11_BLEND_OP_ADD;
rtbDesc.SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
rtbDesc.DestBlendAlpha = D3D11_BLEND_ONE;
rtbDesc.BlendOpAlpha = D3D11_BLEND_OP_ADD;
rtbDesc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

As you can see, the particles are far too "bright" before they fade away. However, any other setting I've tried, I keep getting this type of flickering result: http://postimg.org/image/eell6mrf1/ (static screenshot: http://postimg.org/image/x282i3oin/)

I think a way to fix this would be to sort the particles in the order of their alphas and then use the "normal" blending settings (src and dest as SRC_ALPHA and INV_SRC_ALPHA) but that is out of the question as I'm using the compute shader with append/consume buffers to simulate the particles. Reading the data back to CPU, sorting it and then sending it for rendering would negate half the reasons for using the compute shader and keeping the memory transfers from CPU->GPU only for constant buffers.

Any help would be greatly appreciated!

Advertisement

I believe the problem with your video is that you have depth write and depth testing enabled. Usually, you want depth write disabled for particles.

I believe the problem with your video is that you have depth write and depth testing enabled. Usually, you want depth write disabled for particles.

That's what I thought at first as well but disabling depth writing didn't work: http://postimg.org/image/67a906t6n/

I tried disabling depth testing all together as well but that didn't help either.


That's what I thought at first as well but disabling depth writing didn't work: http://postimg.org/image/67a906t6n/
I tried disabling depth testing all together as well but that didn't help either.

Huh? Your link points to a screenshot of the depthstencil state. It looks like you have depth testing enabled and depth writing disabled, which is what you want.

Using "normal" blending settings (src: SRC_ALPHA, dest: INV_SRC_ALPHA) vs using additive blending will produce very different looks. Generally you would use the former for things like smoke, and the latter for things that emit light, such as fire or glowing things.

So what you use depends on the look you are trying to get. And yes, using normal blending settings means you need to draw your particles back to front to get something that looks "correct". But you should still get something reasonable if you don't bother sorting. Certainly you shouldn't get black boxes around your particles. Are you sure that your particle textures have a proper alpha channel? Can you post a screenshot of the alpha channel of the texture on the GPU? (I know you can do this in PIX, not sure which GPU debugging tools you're using). Also, is your texture using premultiplied alpha?

If you're using additive blending for glowing things, maybe try just drawing fewer particles so the color doesn't wash out so quickly? Or draw them darker. Particle systems are as much art as tech, so it may take a while to get the look you want.


That's what I thought at first as well but disabling depth writing didn't work: http://postimg.org/image/67a906t6n/
I tried disabling depth testing all together as well but that didn't help either.

Huh? Your link points to a screenshot of the depthstencil state. It looks like you have depth testing enabled and depth writing disabled, which is what you want.

Using "normal" blending settings (src: SRC_ALPHA, dest: INV_SRC_ALPHA) vs using additive blending will produce very different looks. Generally you would use the former for things like smoke, and the latter for things that emit light, such as fire or glowing things.

So what you use depends on the look you are trying to get. And yes, using normal blending settings means you need to draw your particles back to front to get something that looks "correct". But you should still get something reasonable if you don't bother sorting. Certainly you shouldn't get black boxes around your particles. Are you sure that your particle textures have a proper alpha channel? Can you post a screenshot of the alpha channel of the texture on the GPU? (I know you can do this in PIX, not sure which GPU debugging tools you're using). Also, is your texture using premultiplied alpha?

If you're using additive blending for glowing things, maybe try just drawing fewer particles so the color doesn't wash out so quickly? Or draw them darker. Particle systems are as much art as tech, so it may take a while to get the look you want.

Thanks for your reply!

I posted the screenshot of the depthstencil state as proof that the settings are indeed correct and that I wasn't just guessing that the settings should be fine.

I switched the particle texture to the one I successfully used in my OpenGL particle system (where I didn't do any sorting and used normal blending settings). I'm not sure if these are the images you requested or not: http://postimg.org/image/okna4xjwv/

Here's the render results with that particle: http://postimg.org/image/ejcxf4jl9/

I have no idea why the particle's alpha isn't showing up properly. I converted the texture from .png to .dds (A8R8G8B8). I'm guessing my OM stage settings are wrong? Here's a screenshot of them: http://postimg.org/image/n7hr3l3r3/

Hope you can help.

Thanks in advance!

EDIT: tried with just the same .png as well so the texture conversion to dds doesn't seem to be a problem

Ok, so let's break it down:

- indeed, your texture is completely transparent outside the main "particle area" (your first screenshot)

- the texture format is BC2_UNORM

- the color for your output pixel (according to your blend states screenshot) is: "SrcColor * SourceAlpha + DestColor * InverseSourceAlpha".

So let's say your current destination pixel has a value of (0.5, 0.5, 0.5, ?).

Then, the outside of your particle texture (0, 0, 0, 0) is drawn on it.

The result should be (0, 0, 0) * 0 + (0.5, 0.5, 0.5) * 1 = (0.5, 0.5, 0.5).

Obviously, that isn't happening though, since in your 2nd screenshot, it seems to make things darker...

The weird thing is, it looks like your particles "cover" up other particles drawn first with varying degrees of opacity. Like one of your particles is completely opaque, and most of the others are not.

What does your shader look like? Ultimately, the alphablending equation depends on the color output from your shader. Are you *just* sampling directly from the particle texture, or are you doing other stuff with the output color/alpha?

The weird results in the http://postimg.org/image/ejcxf4jl9/ screenshot look like you're still using

rtbDesc.SrcBlend = D3D11_BLEND_SRC_ALPHA;
rtbDesc.DestBlend = D3D11_BLEND_DEST_ALPHA;

Did you remember to put that back to 'normal' blending when you switched texture? i.e.

rtbDesc.SrcBlend = D3D11_BLEND_SRC_ALPHA;
rtbDesc.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;

Ok, so let's break it down:

- indeed, your texture is completely transparent outside the main "particle area" (your first screenshot)

- the texture format is BC2_UNORM

- the color for your output pixel (according to your blend states screenshot) is: "SrcColor * SourceAlpha + DestColor * InverseSourceAlpha".

So let's say your current destination pixel has a value of (0.5, 0.5, 0.5, ?).

Then, the outside of your particle texture (0, 0, 0, 0) is drawn on it.

The result should be (0, 0, 0) * 0 + (0.5, 0.5, 0.5) * 1 = (0.5, 0.5, 0.5).

Obviously, that isn't happening though, since in your 2nd screenshot, it seems to make things darker...

The weird thing is, it looks like your particles "cover" up other particles drawn first with varying degrees of opacity. Like one of your particles is completely opaque, and most of the others are not.

What does your shader look like? Ultimately, the alphablending equation depends on the color output from your shader. Are you *just* sampling directly from the particle texture, or are you doing other stuff with the output color/alpha?

Thanks for your reply once again! Indeed, I had totally forgotten about my pixel shader: I was using the compute shader for the first time and got a bit carried away with that I guess: I'm calculating the transparency for the particles based on their lifetime, ie the older they are the more transparent they get. In my pixel shader I was replacing the alpha for the pixel with the one calculated in the compute shader, hence overriding any actual texture alpha. I changed the result to be a multiplication of the transparency found in the compute shader and the actual transparency of the pixel from the texture and got the following result: http://postimg.org/image/knatl7c81/

The weird black-box syndrome is gone biggrin.png However I'm not sure why the texture is of such a low quality once I load it in. Here's what it's supposed to look like (I added the black background in Gimp, it's transparent normally): http://postimg.org/image/d16ecakkf/

Even if I just use the sampled texture color (ie no multiplication), I still get the same result.

Any thoughts on as to why it might be happening?

Thanks in advance once more!

Hmm... does it look any different if you use an uncompressed texture format?

BC2_UNORM (aka DXT3) only gives 16 possible values for alpha so it's pretty poor for smooth gradients, dithering at compression time might help a little.

You're better off using BC3_UNORM (aka DXT5), it uses block compression on the alpha channel and is generally going to produce better results in most circumstances.

This topic is closed to new replies.

Advertisement