【问题标题】:Why does DirectXToolkit ruin my depth testing为什么 DirectX Toolkit 会破坏我的深度测试
【发布时间】:2021-01-25 22:55:43
【问题描述】:

我确定我只是遗漏了一些到目前为止我太盲目而没有注意到的简单步骤,但我似乎根本无法进行深度测试。这适用于 DirectX 11。

应该设置它的代码:

    DXGI_SWAP_CHAIN_DESC swapDesc = { };
    swapDesc.BufferDesc.Width = 0;
    swapDesc.BufferDesc.Height = 0;
    swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    swapDesc.BufferDesc.RefreshRate.Numerator = 0;
    swapDesc.BufferDesc.RefreshRate.Denominator = 1;
    swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    swapDesc.SampleDesc.Count = 1;
    swapDesc.SampleDesc.Quality = 0;

    swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapDesc.BufferCount = 1;
    swapDesc.OutputWindow = hwnd;
    swapDesc.Windowed = TRUE;
    swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapDesc.Flags = 0;

    UINT flg = 0;
#if MAGE_DEBUG
    flg |= D3D11_CREATE_DEVICE_DEBUG;
#endif
    GFX_THROW_INFO(D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
        flg,
        nullptr, 0,
        D3D11_SDK_VERSION, &swapDesc, &mSwap, &mDevice, nullptr,
        &mContext));

    COMptr<ID3D11Resource> backBuffer;
    GFX_THROW_INFO(mSwap->GetBuffer(0, __uuidof(ID3D11Resource), &backBuffer));
    GFX_THROW_INFO(mDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, &mTarget));


    LOG_INFO("Setting depth stencil dimensions ({}, {})", width, height);
    COMptr<ID3D11Texture2D> depthStencil;
    D3D11_TEXTURE2D_DESC texDesc = { };
    texDesc.Width = width;
    texDesc.Height = height;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 1;
    texDesc.Format = DXGI_FORMAT_D32_FLOAT;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    GFX_THROW_INFO(mDevice->CreateTexture2D(&texDesc, nullptr, &depthStencil));

    D3D11_DEPTH_STENCIL_DESC depth = { };
    depth.DepthEnable = TRUE;
    depth.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    depth.DepthFunc = D3D11_COMPARISON_LESS;


    COMptr<ID3D11DepthStencilState> depthState;
    GFX_THROW_INFO(mDevice->CreateDepthStencilState(&depth, &depthState));


    D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = { };
    dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    dsvDesc.Texture2D.MipSlice = 0;
    GFX_THROW_INFO(mDevice->CreateDepthStencilView(depthStencil.Get(), &dsvDesc, &mDepthStencilView));

    mContext->OMSetDepthStencilState(depthState.Get(), 1);
    mContext->OMSetRenderTargets(1, mTarget.GetAddressOf(), mDepthStencilView.Get());

    LOG_INFO("Setting viewport dimensions ({}, {})", width, height);
    D3D11_VIEWPORT vp;
    vp.Width = (float) width;
    vp.Height = (float) height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0.0f;
    vp.TopLeftY = 0.0f;
    mContext->RSSetViewports(1, &vp);

当然,在每一帧之前我都会调用以下代码:

    mContext->ClearRenderTargetView(mTarget.Get(), color);
    mContext->ClearDepthStencilView(mDepthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);

但不幸的是,结果最终是这样的(请注意,孤岛危机纳米服模型在地精头部后面)我相信这也可能是地精模型即使在单独时也渲染不正确但还没有弄清楚的原因还没有。

Example 1

只有妖精,从一个角度看

Example 2

如果有人能帮我弄清楚它为什么不起作用,我将不胜感激!

编辑

经过一些更令人沮丧的测试后,我发现深度测试被破坏了,因为我使用 DirectX ToolKit 的 SpriteBatch 和 SpriteFont 类进行了一些测试文本渲染。有没有人遇到过这个问题?除了文本渲染和加载 dds 纹理之外,我真的不想要/不需要该工具包,所以我希望如果我想使用这些类,我不需要大幅更改现有代码?

【问题讨论】:

    标签: c++ graphics directx depth-testing directxtk


    【解决方案1】:

    DirectX 工具包 不像旧版 D3DX9/D3DX10 精灵那样“捕获/恢复”状态。这是低效的,并且依赖于一些 hacky 后门功能来捕获 Direct3D 10+ 的“状态块”。在大多数情况下,您已经准备好设置大部分常用状态,以便为下一次绘制调用做好准备。

    相反,我已经完整记录了每个类影响的所有状态。您应该在 DirectX 工具包 对象呈现之后更改所有必需的状态。例如,SpriteBatch docs 状态:

    SpriteBatch 使用以下状态:

    • 混合状态
    • 恒定缓冲区(顶点着色器阶段,插槽 0)
    • DepthStencilState
    • 索引缓冲区
    • 输入布局
    • 像素着色器
    • 原始拓扑
    • 光栅化状态
    • SamplerState(像素着色器阶段,插槽 0)
    • 着色器资源(像素着色器阶段,插槽 0)
    • 顶点缓冲区(插槽 0)
    • 顶点着色器

    简而言之,您只需在调用SpriteBatch::End 后将 DepthStencilState 设置为您想要使用的状态。

    作为状态管理的一般习惯,您应该设置每一帧所依赖的所有状态。虽然在 Direct3D 11 中,您调用 Present 时的“最后状态”在下一帧开始时仍然存在,但 DirectX 12 并非如此。因此,您应该养成在开始时的习惯一个新的框架设置所有内容,如当前渲染目标、视口、您希望在整个场景中呈现的渲染状态等。

    例如,大多数“HUD”渲染是最后完成的,因此 SpriteBatch 的状态更改通常会在下一帧的开始时重置——同样,假设您在帧开始时设置了所需的状态,而不是假设它在许多帧中保持不变。

    TL;DR:将此代码移至您每帧清除渲染目标之后:

        mContext->OMSetDepthStencilState(depthState.Get(), 1);
        mContext->OMSetRenderTargets(1, mTarget.GetAddressOf(), mDepthStencilView.Get());
    
        D3D11_VIEWPORT vp = { 0.f, 0.f, float(width), float(height), D3D11_MIN_DEPTH, D3D11_MAX_DEPTH };
        mContext->RSSetViewports(1, &vp);
    

    【讨论】:

    • 非常感谢!在每帧之前添加RSSetViewportsOMSetDepthStencilStateOMSetRenderTargets 之后,现在一切似乎都正常了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2013-06-25
    • 2013-06-07
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多