Прозрачность на двух прямоугольниках в DirectX, один за другим - я вижу фон окна вместо второй текстуры

У меня есть приложение DirectX 11 C++, которое отображает два прямоугольника с текстурами и текстом. Обе текстуры взяты из ресурсов TGA (с добавлением альфа-канала).

Когда я запускаю программу, я получаю результат:

введите здесь описание изображения

Что случилось? Взгляните повнимательнее:

введите здесь описание изображения

Углы прямоугольников прозрачны (так и должно быть). Непрозрачность остальных текстур установлена ​​на 30% (и это тоже хорошо работает).

Но когда одна текстура (назовем ее texture1) находится поверх другой (texture2):

Углы текстуры1 прозрачны. Но за ними я вижу фон окна, а не текстуру2.

Другими словами, прозрачность текстуры взаимодействует с фоном окна, а не с текстурами за ним.

Что я сделал не так? Какая часть моей программы может отвечать за это? Параметры смешивания, состояния рендеринга, код шейдера...?

В моем шейдере я установил:

technique10 RENDER{
    pass P0{
        SetVertexShader(CompileShader( vs
...
//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();
}
0, VS())); SetPixelShader(CompileShader( ps
...
//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();
}
0, PS())); SetBlendState(SrcAlphaBlendingAdd, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF); } }

P.S. Конечно, когда я меняю фон окна с синего на другой цвет, элементы по-прежнему сохраняют прозрачность (углы не синие).


редактировать:

Согласно @ComicSansMS (во всяком случае, + для ника ;p ), я попытался изменить порядок элементов рендеринга (я также немного переместил меньшую текстуру, чтобы проверить, остается ли ошибка):

введите здесь описание изображения

Меньшая текстура теперь позади большей. Но проблема с углами осталась (теперь она появляется на второй текстуре). Я почти уверен, что отрисовываю прямоугольник позади ДО того, как отрисую прямоугольник выше (я вижу порядок строк кода).

Мой трафарет глубины:

    //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);

Функция рендеринга:

...
//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();
}

Состояние смеси:

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);

person PolGraphic    schedule 21.07.2014    source источник


Ответы (1)


Ваш порядок розыгрыша, вероятно, неправильный.

Смешивание не взаимодействует с пикселями объекта позади него, оно взаимодействует с пикселями, которые в данный момент находятся в буфере кадра.

Таким образом, если вы нарисуете прямоугольник впереди перед прямоугольником сзади, его операция смешивания будет взаимодействовать с тем, что находится в буфере кадра в этой точке (то есть с фоном).

Решение, очевидно, состоит в том, чтобы отсортировать ваши объекты по их глубине в пространстве обзора и рисовать сзади наперед, хотя иногда это легче сказать, чем сделать (особенно когда допускаются произвольные перекрытия).

Другая проблема заключается в том, что вы рисуете оба прямоугольника с одинаковым значением глубины. Ваш тест глубины установлен на D3D11_COMPARISON_LESS, поэтому, как только треугольник будет нарисован на пикселе, другой треугольник не пройдет тест глубины для этого пикселя и вообще не будет нарисован. Это объясняет результаты, которые вы получаете при изменении порядка рисования.

Обратите внимание, что если вы рисуете объекты задом наперед, нет необходимости выполнять тест глубины вообще, поэтому в этом случае вы можете просто отключить его. В качестве альтернативы вы можете попытаться расположить объекты вдоль оси глубины, задав им разные значения Z, или просто переключиться на D3D11_COMPARISON_LESS_EQUAL для проверки глубины.

person ComicSansMS    schedule 21.07.2014
comment
Я не уверен, что это порядок их рендеринга. Я имею в виду, что когда я меняю порядок, меньший прямоугольник находится за большим (я не вижу меньшего, который скрыт за большим). Может что-то с глубиной или какими-то буферами? - person PolGraphic; 21.07.2014
comment
@PolGraphic Каковы значения Z для ваших прямоугольников и как настроен ваш тест глубины? - person ComicSansMS; 21.07.2014
comment
Я обновил свой вопрос - надеюсь, я дал вам всю информацию, которую вы хотели. Я не очень понимаю Z-значения для прямоугольников - я работаю с 2d объектами, я отправляю в шейдер только 2d положение углов (z и w устанавливаются шейдером в z=0, w=1). Порядок отправки их в шейдер решает, какой прямоугольник будет впереди (это работает), а прозрачность — нет. - person PolGraphic; 21.07.2014
comment
РАБОТАЕТ КРАСИВО. Спасибо мужик - за терпение, а так же точный и быстрый ответ. Это удивительное сообщество. P.S. Как вы предложили, я решил использовать D3D11_COMPARISON_LESS_EQUAL. - person PolGraphic; 21.07.2014