У меня есть приложение DirectX 11 C ++, которое отображает два прямоугольника с текстурами и немного текста.
Обе текстуры взяты из ресурсов TGA (с добавленным альфа-каналом).
Когда я запускаю программу, я получаю результат:
В чем дело? Присмотритесь:
Углы прямоугольников прозрачны (и они должны быть). Остальные текстуры имеют непрозрачность 30% (и это тоже хорошо работает).
Но когда одна текстура (давайте назовем это texture1) над другим (texture2):
Углы текстуры1 прозрачны.
Но за ними я вижу фон окна, а не texture2.
Другими словами, прозрачность текстуры взаимодействует с фоном окна, а не с текстурами позади него.
Что я сделал не так? Какая часть моей программы может быть ответственна за это? Параметры смешивания, состояния рендеринга, код шейдера …?
В моем шейдере я установил:
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);
}
}
Постскриптум
Конечно, когда я изменяю фон окна с синего на другой цвет, элементы по-прежнему имеют прозрачность (углы не синие).
редактировать:
В соответствии с @ComicSansMS
(в любом случае для nick; 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);
Ваш порядок рисования, вероятно, неверный.
Смешивание не взаимодействует с пикселями объекта позади него, оно взаимодействует с пикселями, которые в данный момент находятся в буфере кадра.
Поэтому, если вы рисуете прямоугольник спереди перед прямоугольником сзади, его операция смешивания будет взаимодействовать с тем, что находится в буфере кадров в этой точке (то есть фоном).
Очевидно, что решение состоит в том, чтобы отсортировать ваши объекты по глубине в поле зрения и рисовать сзади-спереди, хотя иногда это легче сказать, чем сделать (особенно когда допускается произвольное перекрытие).
Другая проблема заключается в том, что вы рисуете оба прямоугольника с одинаковым значением глубины. Ваш тест глубины установлен на D3D11_COMPARISON_LESS
, поэтому, как только треугольник нарисован на пикселе, другой треугольник не пройдет тест глубины для этого пикселя и не будет нарисован вообще. Это объясняет результаты, которые вы получаете при смене порядка рисования.
Обратите внимание, что если вы рисуете объекты задом наперед, вам вообще не нужно выполнять тест глубины, поэтому вы можете просто отключить его в этом случае. В качестве альтернативы вы можете попытаться расположить объекты вдоль оси глубины, задав для них разные значения Z, или просто переключитесь на D3D11_COMPARISON_LESS_EQUAL
для проверки глубины.