Advertisement

Alpha burning through render targets

Started by September 11, 2018 09:40 PM
5 comments, last by DividedByZero 6 years, 4 months ago

Hi Guys,

I have a problem where rendering direct to the back buffer is fine. But if I create a render target and draw to it, then render it to the back buffer, the sprite transparency eats holes through anything on the RT. Which then reveals the back buffer itself.

FxhoreZ.png

On the right side the render target is coloured a dark red to highlight the problem.

The blend state is being created and set early on (shortly after context creation) and is working ok as the back buffer is behaving as expected.


	// Create default blend state
	ID3D11BlendState* d3dBlendState = NULL;
	D3D11_BLEND_DESC omDesc;
	ZeroMemory(&omDesc, sizeof(D3D11_BLEND_DESC));
	omDesc.RenderTarget[0].BlendEnable = true;
	omDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	omDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	omDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	omDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	omDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	omDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	omDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

	if (FAILED(d3dDevice->CreateBlendState(&omDesc, &d3dBlendState)))
		return E_WINDOW_DEVICE_BLEND_STATE;

	d3dContext->OMSetBlendState(d3dBlendState, 0, 0xffffffff);
	if (d3dBlendState)
		d3dBlendState->Release();

Any ideas would be greatly appreciated.

Thanks in advance.

If I understand correctly, you draw both sprites to the red render target and then draw that one to the final window/backbuffer. The blend equation for the alpha value replaces whatever is in the render target's alpha channel by the sprite's alpha value. So the front sprite's surrounding pixels will all have an alpha value of zero, meaning full transparency. If you'd check their rgb values, they will probably be correct. But the alpha value of zero simply throws them all away. I guess using the same blend equation for color and alpha should fix this?

Advertisement
27 minutes ago, Koen said:

If I understand correctly, you draw both sprites to the red render target and then draw that one to the final window/backbuffer.

Yep, that's the one.

Ideally, I'd like to use the render target like as if it were a Photoshop layer.

 

I guess using the same blend equation for color and alpha should fix this?

I'll have to see if I can get my head around this. At the moment I am using an example of a default blend state as found on the MSDN.

 

Hang on a sec. Fiddling around I managed to get it to work.

TL9TLBI.png

 

I changed this line;

omDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;        // D3D11_BLEND_ZERO

 

I'll have to do some serious reading up on this as I admit, I don't really know what is going on with these different blend masks.

2 minutes ago, DarkRonin said:

I'll have to see if I can get my head around this. At the moment I am using an example of a default blend state as found on the MSDN.

For the color channels blending you take source alpha into account, but for the alpha channel, you simply replace the destination by the source alpha. So when you draw a sprite to the render target, all covered pixels outside of the knight will end up with an alpha value of zero, so fully transparent. Try this instead:


	omDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	omDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	omDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	omDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
	omDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
	omDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;

It can be easier to just look at what's happening by using a debugger like renderdoc. It lets you see the history of a pixel.

 

 

46 minutes ago, DarkRonin said:

I changed this line;

 



omDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;        // D3D11_BLEND_ZERO

 

In this case this works because the only alpha values are zero and one. With this change you're adding source alpha to destination alpha, so as long as at least one of them is one, the end result will be an alpha value of one. Take the pixels between the feet of the knight in front. The render target contains red or in rgba (1,0,0,1). The sprite's transparent pixel is (0,0,0,0). With your first blend state you'd have


result alpha = D3D11_BLEND_ONE * source alpha + D3D11_BLEND_ZERO * destination alpha

or

result alpha = D3D11_BLEND_ONE * 0 + D3D11_BLEND_ZERO * 1

This leads to an alpha value of zero. So even though the red backgroud rgb is still there, it gets blended away when drawing the render target to the final backbuffer, because of the 0 alpha value. When you replace D3D11_BLEND_ZERO like you did, the resulting alpha value is 1, and the red rgb is fully visible. With alpha values different from zero or one this will not work.

Try making the background of your sprites semi-transparent and see what happens.

Thanks for your advice, Koen :)

Taking a look at RenderDoc to see if I can visualise better what is happening with different blend techniques.

This topic is closed to new replies.

Advertisement