Transparency on two rectangles in DirectX, one behind another - I see the background of window instead the second texture

放肆的年华 提交于 2019-12-11 13:55:56

问题


I have an DirectX 11 C++ application that displays two rectangles with textures and some text. Both textures are taken from TGA resources (with alpha channel added).

When I run the program, I get the result:

What's wrong? Take a closer look:

The corners of the rectangles are transparent (and they should be). The rest of textures are set to be 30% opacity (and it works well too).

But, when one texture (let's call it texture1) is over another (texture2):

The corners of texture1 are transparent. But behind them I see the background of window, instead of texture2.

In other words, transparency of texture interacts with the background of window, not with the textures behind it.

What have I done wrong? What part of my program can be responsible for it? Blending options, render states, shader code...?

In my shader, I set:

technique10 RENDER{
    pass P0{
        SetVertexShader(CompileShader( vs_4_0, VS()));      
        SetPixelShader(CompileShader( ps_4_0, PS()));
        SetBlendState(SrcAlphaBlendingAdd, float4(0.0f, 0.0f, 0.0f, 0.0f), 
            0xFFFFFFFF);
    }    
}

P.s. Of course, when I change the background of window from blue to another colour, the elements still have the transparency (the corners aren't blue).


edit:

According to @ComicSansMS (+ for nick, anyway ;p ), I've tried to change to order of render elements (I've also moved the smaller texture a bit, to check if the error remains):

The smaller texture is now behind the bigger one. But the problem with corners remains (now it appears on the second texture). I am almost sure that I draw the rectangle behind BEFORE I render the rectangle above (I see the code's lines order).

My depth stencil:

    //initialize the description of the stencil state
    ZeroMemory(depthStencilsDescs, sizeof(*depthStencilsDescs));

    //set up the description of the stencil state
    depthStencilsDescs->DepthEnable = true;
    depthStencilsDescs->DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    depthStencilsDescs->DepthFunc = D3D11_COMPARISON_LESS;

    depthStencilsDescs->StencilEnable = true;
    depthStencilsDescs->StencilReadMask = 0xFF;
    depthStencilsDescs->StencilWriteMask = 0xFF;

    //stencil operations if pixel is front-facing
    depthStencilsDescs->FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthStencilsDescs->FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
    depthStencilsDescs->FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthStencilsDescs->FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

    //stencil operations if pixel is back-facing
    depthStencilsDescs->BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthStencilsDescs->BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
    depthStencilsDescs->BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthStencilsDescs->BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

    //create the depth stencil state
    result = device->CreateDepthStencilState(depthStencilsDescs, depthStencilState2D);

The render function:

...
//clear the back buffer
context->ClearRenderTargetView(myRenderTargetView, backgroundColor); //backgroundColor

//clear the depth buffer to 1.0 (max depth)
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
context->OMSetDepthStencilState(depthStencilState2D, 1);
context->VSSetShader(getVertexShader(), NULL, 0);
context->PSSetShader(getPixelShader(), NULL, 0);
for(...){
    rectangles[i]->render();
}

The blend state:

D3D11_BLEND_DESC blendDesc;
ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC) );
blendDesc.AlphaToCoverageEnable = false;
blendDesc.IndependentBlendEnable = false;        
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;

blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;      
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;     
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL ;

ID3D11BlendState * blendState;

if (FAILED(device->CreateBlendState(&blendDesc, &blendState))){
}

context->OMSetBlendState(blendState,NULL,0xffffffff);

回答1:


Your draw order is probably wrong.

Blending does not interact with the pixels of the object behind it, it interacts with the pixels that are currently in the frame buffer.

So if you draw the rectangle in front before the rectangle in the back, its blending operation will interact with what is in the frame buffer at that point (that is, the background).

The solution is obviously to sort your objects by their depth in view space and draw from back-to-front, although that is sometimes easier said than done (especially when allowing arbitrary overlaps).

The other problem seems to be that you draw both rectangles at the same depth value. Your depth test is set to D3D11_COMPARISON_LESS, so as soon as a triangle is drawn on a pixel, the other triangle will fail the depth test for that pixel and won't get drawn at all. This is explains the results you get when swapping the drawing order.

Note that if you draw objects back-to-front there is no need to perform a depth test at all, so you might just want to switch it off in this case. Alternatively, you can try to arrange the objects along the depth axis by giving them different Z values, or just switch to D3D11_COMPARISON_LESS_EQUAL for the depth test.



来源:https://stackoverflow.com/questions/24864948/transparency-on-two-rectangles-in-directx-one-behind-another-i-see-the-backgr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!