D3D11:对纹理的渲染(深度)会产生红色方块,正常的渲染效果

时间:2019-04-11 12:59:42

标签: c++ directx-11 direct3d

我目前正在D3D项目中工作,想实现定向阴影映射。我按照Microsoft Guide进行了所有设置,但这只是行不通。

我已经创建了一个2D纹理对象,一个深度模具视图和一个着色器资源视图,并使用以下描述进行设置:

    D3D11_TEXTURE2D_DESC shadowMapDesc;
    ZeroMemory(&shadowMapDesc, sizeof(D3D11_TEXTURE2D_DESC));
    shadowMapDesc.Width = width;
    shadowMapDesc.Height = height;
    shadowMapDesc.MipLevels = 1;
    shadowMapDesc.ArraySize = 1;
    shadowMapDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
    shadowMapDesc.SampleDesc.Count = 1;
    shadowMapDesc.SampleDesc.Quality = 0;
    shadowMapDesc.Usage = D3D11_USAGE_DEFAULT;
    shadowMapDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    shadowMapDesc.CPUAccessFlags = 0;
    shadowMapDesc.MiscFlags = 0;

    ID3D11Device& d3ddev = dev.getD3DDevice();

    uint32_t *initData = new uint32_t[width * height];
    ZeroMemory(initData, sizeof(uint32_t) * width * height);

    D3D11_SUBRESOURCE_DATA data;
    ZeroMemory(&data, sizeof(D3D11_SUBRESOURCE_DATA));
    data.pSysMem = initData;
    data.SysMemPitch = sizeof(uint32_t) * width;
    data.SysMemSlicePitch = 0;

    HRESULT hr = d3ddev.CreateTexture2D(&shadowMapDesc, &data, &texture_);

    D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
    ZeroMemory(&depthStencilViewDesc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
    depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    depthStencilViewDesc.Texture2D.MipSlice = 0;

    hr = d3ddev.CreateDepthStencilView(texture_, &depthStencilViewDesc, &stencilView_);

    D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
    ZeroMemory(&shaderResourceViewDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    shaderResourceViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
    shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    shaderResourceViewDesc.Texture2D.MipLevels = 1;
    shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;

    hr = d3ddev.CreateShaderResourceView(texture_, &shaderResourceViewDesc, &shaderView_);

在这些步骤之间,还进行了其他错误检查,但所有创建功能均成功返回。然后,我使用以下功能绑定纹理,渲染场景并取消绑定纹理:

void D3DDepthTexture2D::bindAsTarget(D3DDevice& dev)
{
    dev.getDeviceContext().ClearDepthStencilView(stencilView_, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    // Bind target
    dev.getDeviceContext().OMSetRenderTargets(0, 0, stencilView_);

    // Set viewport
    dev.setViewport(static_cast<float>(width_), static_cast<float>(height_), 0.0f, 0.0f);
}

void D3DDepthTexture2D::unbindAsTarget(D3DDevice& dev, float width, float height)
{
    // Unbind target
    dev.resetRenderTarget();

    // Reset viewport
    dev.setViewport(width, height, 0.0f, 0.0f);
}

我的“渲染到深度纹理”例程基本上是这样的(删除了所有不必要的细节):

camera = buildCameraFromLight(light);
setCameraCBuffer(camera);
bindTexture();
activateShader();
for(Object j : objects) {setTransformationCBuffer(j); renderObject(j);}
deactivateShader();
unbindTexture();

从光源的角度将场景渲染到正常的渲染目标(屏幕)会生成正确的图像(既是实际图像,也只是渲染深度值)。我使用了一个简单的顶点着色器,该顶点着色器仅转换了顶点,而一个像素着色器根本不执行任何操作,或者返回了深度值(我尝试了这两个方法,由于我们不在乎颜色缓冲区,因此不会改变最终结果)

清除纹理并将其渲染后,我将其渲染到屏幕的四边形上,但我得到的只是一个红色正方形-深度值为1.0f,即清除纹理的值。我真的无所适从,我尝试了一切,通过在线教程实施了每种可能的解决方案,或者自己改变了一切,但是没有任何帮助。这是我已经检查过的所有内容的列表:

  • 所有FAILED(hr)调用均返回false,控制台未打印任何错误消息
  • 我测试了通过将几何图形及其深度值(z / w)渲染到屏幕上是否可以正确转换几何图形,效果良好并且看起来正确
  • 我测试了在片段着色器中计算深度值并渲染到正常的渲染目标(基本上是尝试将我的颜色缓冲区渲染为纹理)而不是深度模板纹理的方法,但这还是无效的,红色正方形
  • 我为阴影贴图和视图测试了不同的格式和格式组合,这要么导致创建失败,要么没有改变
  • 我检查了在渲染调用期间是否将设置纹理和取消设置纹理作为渲染目标之间的任何调用是否将深度模板目标重置为其他东西-情况并非如此
  • 我已经调试了我的“纹理到屏幕/四边形”渲染例程,并且可以与其他纹理一起正常使用,因此实际上我正在查看深度纹理的外观
  • 我更改了几何形状和摄影机的视角,以查看是否可以在深度纹理中看到任何东西-不会
  • 我遇到了this similar StackOverflow problem,并检查了我的默认深度模板缓冲区是否具有与我的纹理相同的尺寸,AA设置等-并且确实如此(计数为1,质量为0)

我真的不知道怎么回事,我已经尝试调试了好几个小时。我希望这里有人可以给我有关我做错了什么或我可以尝试解决的问题的任何建议。我在Direct3D11中使用C ++ 11。

注意:我无法使用NSight或任何Visual Studio工具调试任何此类工具,因为它们目前似乎无法在我的系统上正常工作,并且我没有任何管理权限来修复其中的任何一个。我现在只需要处理它。我希望所给的信息和代码示例足以使我对我也可以尝试实现的工作有一个大概的了解。

谢谢。

1 个答案:

答案 0 :(得分:1)

我让NSight可以工作并对其进行了调试。事实证明深度纹理是正确创建的,并填充了深度和模板数据,我只是忘记了所有深度信息都存储在第一个通道中,所以我忽略了g和b数据,并使用1.0作为a并起作用。使用g和b通道使整体变红(也许有人想添加它并解释原因)。

一旦我可以观察到着色器中存在的纹理,调试起来就会容易得多-我应该早先使用NSight或RenderDoc之类的调试工具。感谢@EgorShkorov的建议。