Я готовлю все в небольшом моем DirectX 11.0 проекте для отложенного конвейера рендеринга. Однако у меня было довольно много проблем с выборкой буфера глубины из пиксельного шейдера.
Сначала я определяю текстуру глубины и ее вид ресурса шейдера:
D3D11_TEXTURE2D_DESC depthTexDesc;
ZeroMemory(&depthTexDesc, sizeof(depthTexDesc));
depthTexDesc.Width = nWidth;
depthTexDesc.Height = nHeight;
depthTexDesc.Format = DXGI_FORMAT_R32_TYPELESS;
depthTexDesc.Usage = D3D11_USAGE_DEFAULT;
depthTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
depthTexDesc.MipLevels = 1;
depthTexDesc.ArraySize = 1;
depthTexDesc.SampleDesc.Count = 1;
depthTexDesc.SampleDesc.Quality = 0;
depthTexDesc.CPUAccessFlags = 0;
depthTexDesc.MiscFlags = 0;
hresult = d3dDevice_->CreateTexture2D(&depthTexDesc, nullptr, &depthTexture_);
D3D11_DEPTH_STENCIL_VIEW_DESC DSVDesc;
ZeroMemory(&DSVDesc, sizeof(DSVDesc));
DSVDesc.Format = DXGI_FORMAT_D32_FLOAT;
DSVDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
DSVDesc.Texture2D.MipSlice = 0;
hresult = d3dDevice_->CreateDepthStencilView(depthTexture_, &DSVDesc, &depthView_);
D3D11_SHADER_RESOURCE_VIEW_DESC gbDepthTexDesc;
ZeroMemory(&gbDepthTexDesc, sizeof(gbDepthTexDesc));
gbDepthTexDesc.Format = DXGI_FORMAT_R32_FLOAT;
gbDepthTexDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
gbDepthTexDesc.Texture2D.MipLevels = 1;
gbDepthTexDesc.Texture2D.MostDetailedMip = -1;
d3dDevice_->CreateShaderResourceView(depthTexture_, &gbDepthTexDesc, &gbDepthView_);
Вот соответствующая часть моей функции рендеринга:
float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);
d3dContext_->ClearDepthStencilView(depthView_, D3D11_CLEAR_DEPTH, 1.0f, 0);
// GBuffer packing pass (in the future): /////////////////////////////////////////
d3dContext_->OMSetRenderTargets(1, &backBufferTarget_, depthView_);
unsigned int nStride = sizeof(Vertex);
unsigned int nOffset = 0;
d3dContext_->IASetInputLayout(inputLayout_);
d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer_, &nStride, &nOffset);
d3dContext_->IASetIndexBuffer(indexBuffer_, DXGI_FORMAT_R32_UINT, 0);
d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3dContext_->VSSetShader(firstVS_, 0, 0);
d3dContext_->PSSetShader(firstPS_, 0, 0);
d3dContext_->DrawIndexed(nIndexCount_, 0, 0);
d3dContext_->OMSetRenderTargets(1, &backBufferTarget_, nullptr);
d3dContext_->VSSetShader(secondVS_, 0, 0);
d3dContext_->PSSetShader(secondPS_, 0, 0);
d3dContext_->PSGetShaderResources(0, 1, &gbDepthView_);
d3dContext_->PSSetSamplers(0, 1, &colorMapSampler_);
d3dContext_->DrawIndexed(nIndexCount_, 0, 0);
swapChain_->Present(0, 0);
В этой временной реализации firstVS_ и secondVS_ идентичны, и их единственная функция состоит в том, чтобы выполнять все преобразования и передавать данные в PS.
И, наконец, вот firstPS_ и secondPS_:
// firstPS_
float4 main(PS_Input frag) : SV_TARGET
{
return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
// secondPS_
Texture2D<float> depthMap_ : register(t0);
SamplerState colorSampler_ : register(s0);
float4 main(PS_Input frag) : SV_TARGET
{
float4 psOut;
psOut.xyz = depthMap_.Sample(colorSampler_, frag.tex0).xxx;
psOut.w = 1.0f;
return psOut;
}
Итак, мои актуальные вопросы:
1) Весь этот код компилируется без проблем, но когда я сэмплирую буфер глубины, он просто становится черным. Я читал, что это может быть вызвано вашей глубиной & вид трафарета, связанный D3D11DeviceContext::OMSetRenderTargets()
в то время, когда вы хотите сэмплировать буфер глубины. Я исправил это, но буфер все еще черный. Я проверил графический отладчик, но безуспешно. Итак, мой буфер глубины записывается неправильно или я выполняю выборку неправильно? firstPS_ работает нормально.
2) Говоря о сэмплировании, в книге, которую я использую, просто говорится «мы будем использовать точечный сэмплер», но я понятия не имею, что именно имеется в виду. Сейчас я просто использую стандартный образец текстурной карты, но есть ли что-то еще, с чем я должен сэмплировать?
3) Кроме того, книга использует SamplerState.Gather()
функция в secondPS_, но когда я попытался, он пожаловался, что «выражение не может быть сопоставлено с набором инструкций пиксельного шейдера». Является Gather()
ошибка в книге, или это мой графический процессор (уровень функциональности D3D 11.0), который не понимает, что это такое? Является Sample()
достаточно хорош для того, что я хочу сделать? Первоначальное использование Gather()
был в контексте создания силуэта вокруг объектов в буфере глубины.
4) Я пытался заставить secondVS_ рисовать только полноэкранный квад, но FXC жаловался на мое использование SV_VertexID
как «недействительный», говоря, что мой тип должен быть целым, даже если он уже был. Я где-то читал, что SV_VertexID
может использоваться только первым VS в конвейере. Это проблема здесь? Как мне решить это в данном конкретном случае? В моем текущем неэффективном решении, проблема вызвана ультрафиолетом?
1) Вы назвали PSGetShaderResources вместо PSSetShaderResources. Кроме того, MostDetailedMip должно быть 0, а не -1.
2) «Точечный сэмплер» — это просто сэмплер текстуры с полем FILTER, установленным на что-то вроде D3D11_FILTER_MIN_MAG_MIP_POINT.
3) Gather — это функция на Texture2D, а не SamplerState, как вы заявили.
4) Вы получаете эту ошибку, если вы компилируете, используя vs_4_0, попробуйте vs_5_0.