简体   繁体   English

Direct3D 11:为什么深度缓冲不起作用,立方体继续显示不正确?

[英]Direct3D 11: Why does the depth buffer not work and the cube continues to display incorrectly?

I wanted to draw a 3D cube, but it doesn't display correctly.我想画一个 3D 的立方体,但是显示不正确。 That is, the Z buffer (depth buffer) does not work.即Z缓冲(深度缓冲)不起作用。

The initialization of the depth buffer occurs in the InitDepthBuffer method, which I copied from the manual from Microsoft.深度缓冲区的初始化发生在 InitDepthBuffer 方法中,我从 Microsoft 的手册中复制了该方法。 The InitDepthBuffer method is called in the InitD3D method below. InitDepthBuffer方法在下面的InitD3D方法中被调用。

Why "cube" is not displayed correctly and how to fix the program?为什么“立方体”显示不正确以及如何修复程序?

My Game.cpp我的游戏.cpp

// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")

// define the screen resolution
#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600

// global declarations
IDXGISwapChain* swapchain;             // the pointer to the swap chain interface
ID3D11Device* dev;                     // the pointer to our Direct3D device interface
ID3D11DeviceContext* devcon;           // the pointer to our Direct3D device context
ID3D11RenderTargetView* backbuffer;    // the pointer to our back buffer
ID3D11InputLayout* pLayout;            // the pointer to the input layout
ID3D11VertexShader* pVS;               // the pointer to the vertex shader
ID3D11PixelShader* pPS;                // the pointer to the pixel shader
ID3D11Buffer* pVBuffer;                // the pointer to the vertex buffer
ID3D11Buffer* pIBuffer;
ID3D11Buffer* wvpConstBuffer;
ID3D11ShaderResourceView* pTexture;    // the texture
ID3D11SamplerState* pSamplerState;
ID3D11RasterizerState* pRasterState;

ID3D11Texture2D* pDepthStencil = NULL;
ID3D11DepthStencilState* pDSState;
ID3D11DepthStencilView* pDSV;

// a struct to define a single vertex
struct VERTEX { FLOAT X, Y, Z, texX, texY; };

struct ConstantBuffer
{
    XMMATRIX mWorld;
    XMMATRIX mView;
    XMMATRIX mProjection;
};

XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection;

// function prototypes
void InitD3D(HWND hWnd);    // sets up and initializes Direct3D
void RenderFrame(void);     // renders a single frame
void CleanD3D(void);        // closes Direct3D and releases memory
void InitGraphics(void);    // creates the shape to render
void InitPipeline(void);    // loads and prepares the shaders

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = L"WindowClass";

    RegisterClassEx(&wc);

    RECT wr = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

    hWnd = CreateWindowEx(NULL,
        L"WindowClass",
        L"My Game",
        WS_OVERLAPPEDWINDOW,
        300,
        300,
        wr.right - wr.left,
        wr.bottom - wr.top,
        NULL,
        NULL,
        hInstance,
        NULL);

    ShowWindow(hWnd, nCmdShow);

    // set up and initialize Direct3D
    InitD3D(hWnd);

    // enter the main loop:

    MSG msg;

    while (TRUE)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if (msg.message == WM_QUIT)
                break;
        }

        RenderFrame();
    }

    // clean up DirectX and COM
    CleanD3D();

    return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        return 0;
    } break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

void InitDepthBuffer()
{
    D3D11_TEXTURE2D_DESC descDepth;
    descDepth.Width = SCREEN_WIDTH;
    descDepth.Height = SCREEN_HEIGHT;
    descDepth.MipLevels = 1;
    descDepth.ArraySize = 1;
    descDepth.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
    descDepth.SampleDesc.Count = 1;
    descDepth.SampleDesc.Quality = 0;
    descDepth.Usage = D3D11_USAGE_DEFAULT;
    descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    descDepth.CPUAccessFlags = 0;
    descDepth.MiscFlags = 0;
    dev->CreateTexture2D(&descDepth, NULL, &pDepthStencil);

    D3D11_DEPTH_STENCIL_DESC dsDesc;

    // Depth test parameters
    dsDesc.DepthEnable = true;
    dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    dsDesc.DepthFunc = D3D11_COMPARISON_LESS;

    // Stencil test parameters
    dsDesc.StencilEnable = true;
    dsDesc.StencilReadMask = 0xFF;
    dsDesc.StencilWriteMask = 0xFF;

    // Stencil operations if pixel is front-facing
    dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
    dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

    // Stencil operations if pixel is back-facing
    dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
    dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

    dev->CreateDepthStencilState(&dsDesc, &pDSState);

    D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
    descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
    descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    descDSV.Texture2D.MipSlice = 0;

    dev->CreateDepthStencilView(pDepthStencil, // Depth stencil texture
        &descDSV, // Depth stencil desc
        &pDSV);  // [out] Depth stencil view
}

// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
    // create a struct to hold information about the swap chain
    DXGI_SWAP_CHAIN_DESC scd;

    // clear out the struct for use
    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

    // fill the swap chain description struct
    scd.BufferCount = 1;                                   // one back buffer
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;    // use 32-bit color
    scd.BufferDesc.Width = SCREEN_WIDTH;                   // set the back buffer width
    scd.BufferDesc.Height = SCREEN_HEIGHT;                 // set the back buffer height
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;     // how swap chain is to be used
    scd.OutputWindow = hWnd;                               // the window to be used
    scd.SampleDesc.Count = 4;                              // how many multisamples
    scd.Windowed = TRUE;                                   // windowed/full-screen mode
    scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;    // allow full-screen switching

    // create a device, device context and swap chain using the information in the scd struct
    D3D11CreateDeviceAndSwapChain(NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        NULL,
        NULL,
        NULL,
        D3D11_SDK_VERSION,
        &scd,
        &swapchain,
        &dev,
        NULL,
        &devcon);


    // get the address of the back buffer
    ID3D11Texture2D* pBackBuffer;
    swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // use the back buffer address to create the render target
    dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
    pBackBuffer->Release();

    InitDepthBuffer();
    // set the render target as the back buffer
    devcon->OMSetRenderTargets(1, &backbuffer, pDSV);
    devcon->OMSetDepthStencilState(pDSState, 1);

    // Set the viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = SCREEN_WIDTH;
    viewport.Height = SCREEN_HEIGHT;
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;

    devcon->RSSetViewports(1, &viewport);

    InitPipeline();
    InitGraphics();
}


// this is the function used to render a single frame
void RenderFrame(void)
{
    // update WVP matrices
    ConstantBuffer cb;
    cb.mWorld = XMMatrixTranspose(g_World);
    cb.mView = XMMatrixTranspose(g_View);
    cb.mProjection = XMMatrixTranspose(g_Projection);
    devcon->UpdateSubresource(wvpConstBuffer, 0, NULL, &cb, 0, 0);

    // clear the back buffer to a deep blue and the depth buffer
    devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));
    devcon->ClearDepthStencilView(pDSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    // select which vertex buffer to display
    UINT stride = sizeof(VERTEX);
    UINT offset = 0;
    devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
    devcon->IASetIndexBuffer(pIBuffer, DXGI_FORMAT_R32_UINT, 0);
    devcon->VSSetConstantBuffers(0, 1, &wvpConstBuffer);

    // select which primtive type we are using
    devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // draw the vertex buffer to the back buffer
    devcon->DrawIndexed(24, 0, 0);

    // switch the back buffer and the front buffer
    swapchain->Present(0, 0);

    g_World *= XMMatrixRotationY(XM_PI / 12);
    Sleep(100);
}


// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
    swapchain->SetFullscreenState(FALSE, NULL);    // switch to windowed mode

    // close and release all existing COM objects
    pLayout->Release();
    pVS->Release();
    pPS->Release();
    pVBuffer->Release();
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}

void InitTextures()
{
    D3DX11CreateShaderResourceViewFromFile(dev, L"texture.png", NULL, NULL, &pTexture, NULL);

    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory(&sampDesc, sizeof(D3D11_SAMPLER_DESC));
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
    dev->CreateSamplerState(&sampDesc, &pSamplerState);
}

// this is the function that creates the shape to render
void InitGraphics()
{
    // create a triangle using the VERTEX struct
    VERTEX OurVertices[] =
    {                                       // CUBE
        {-0.5f, 0.5f, 0.5f, 0.0f, 0.0f},    // Front
        {0.5f, 0.5f, 0.5f, 1.0f, 0.0f},
        {0.5f, -0.5f, 0.5f, 1.0f, 1.0f},
        {-0.5f, -0.5f, 0.5f, 0.0f, 1.0f},
        
        {-0.5f, 0.5f, -0.5f, 1.0f, 0.0f},    // Back
        {0.5f, 0.5f, -0.5f, 0.0f, 0.0f},
        {0.5f, -0.5f, -0.5f, 0.0f, 1.0f},
        {-0.5f, -0.5f, -0.5f, 1.0f, 1.0f},
    };

    // create the vertex buffer
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));

    bd.Usage = D3D11_USAGE_DYNAMIC;                // write access access by CPU and GPU
    bd.ByteWidth = sizeof(OurVertices);             // size is the VERTEX struct * 3
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;       // use as a vertex buffer
    bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;    // allow CPU to write in buffer

    dev->CreateBuffer(&bd, NULL, &pVBuffer);       // create the buffer

    // copy the vertices into the buffer
    D3D11_MAPPED_SUBRESOURCE ms;
    devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);    // map the buffer
    memcpy(ms.pData, OurVertices, sizeof(OurVertices));                 // copy the data
    devcon->Unmap(pVBuffer, NULL);                                      // unmap the buffer

    unsigned int indices[] =
    {
        0, 1, 2, // front
        0, 2, 3,

        4, 0, 3, // left
        4, 3, 7,

        //4, 5, 6, // back
        //4, 6, 7,

        6, 5, 1, // right
        6, 1, 2,
    };

    // indices
    D3D11_BUFFER_DESC bdIndices;
    bdIndices.Usage = D3D11_USAGE_DEFAULT;
    bdIndices.ByteWidth = sizeof(indices);
    bdIndices.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bdIndices.CPUAccessFlags = 0;
    bdIndices.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = indices;
    InitData.SysMemPitch = 0;
    InitData.SysMemSlicePitch = 0;
    dev->CreateBuffer(&bdIndices, &InitData, &pIBuffer);

    D3D11_BUFFER_DESC bdWVP;
    ZeroMemory(&bdWVP, sizeof(D3D11_BUFFER_DESC));
    bdWVP.Usage = D3D11_USAGE_DEFAULT;
    bdWVP.ByteWidth = sizeof(ConstantBuffer);
    bdWVP.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bdWVP.CPUAccessFlags = 0;
    dev->CreateBuffer(&bdWVP, NULL, &wvpConstBuffer);

    g_World = XMMatrixIdentity();

    XMVECTOR Eye = XMVectorSet(0.0f, 1.0f, -3.0f, 0.0f);
    XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
    g_View = XMMatrixLookAtLH(Eye, At, Up);

    g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, 0.01f, 100.0f);
}

void InitRasterizer()
{
    D3D11_RASTERIZER_DESC raster_desc;
    raster_desc.FillMode = D3D11_FILL_SOLID;
    raster_desc.CullMode = D3D11_CULL_NONE;
    raster_desc.FrontCounterClockwise = false;
    raster_desc.DepthBias = 0;
    raster_desc.DepthBiasClamp = 0.0f;
    raster_desc.SlopeScaledDepthBias = 0.0f;
    raster_desc.DepthClipEnable = true;
    raster_desc.ScissorEnable = false;
    raster_desc.MultisampleEnable = false;
    raster_desc.AntialiasedLineEnable = false;

    dev->CreateRasterizerState(&raster_desc, &pRasterState);
}

// this function loads and prepares the shaders
void InitPipeline()
{
    InitRasterizer();
    InitTextures();
    // load and compile the two shaders
    ID3D10Blob* VS, * PS;
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

    // encapsulate both shaders into shader objects
    dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
    dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

    // set the shader objects
    devcon->VSSetShader(pVS, 0, 0);
    devcon->PSSetShader(pPS, 0, 0);

    // set the texture
    devcon->PSSetShaderResources(0, 1, &pTexture);
    devcon->PSSetSamplers(0, 1, &pSamplerState);

    // off cull mode
    devcon->RSSetState(pRasterState);

    // create the input layout object
    D3D11_INPUT_ELEMENT_DESC ied[] =
    {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
    };

    dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
    devcon->IASetInputLayout(pLayout);
}

shaders.shader着色器.shader

cbuffer ConstantBuffer : register(b0)
{
    matrix World;
    matrix View;
    matrix Projection;
}

Texture2D ObjTexture;
SamplerState ObjSamplerState;

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float2 TexCoord : TEXCOORD;
};

VS_OUTPUT VShader(float4 Pos : POSITION, float4 inTexCoord : TEXCOORD)
{
    VS_OUTPUT output = (VS_OUTPUT)0;
    output.Pos = mul(Pos, World);
    output.Pos = mul(output.Pos, View);
    output.Pos = mul(output.Pos, Projection);
    output.TexCoord = inTexCoord;
    return output;
}

float4 PShader(VS_OUTPUT input) : SV_Target
{
    return ObjTexture.Sample(ObjSamplerState, input.TexCoord);
}

the "cube" “立方体”

I've looked all over but couldn't solve the problem.我已经看了一遍,但无法解决问题。

With a fresh eye today i've noticed that besides things i've mentioned earlier render target view and depth stencil view are using different multisampling settings: render target use 4 samples while depth stencil only 1. In order for them to work together their dimensions and multisampling settings must be exactly the same.今天,我以全新的眼光注意到,除了我之前提到的内容之外,渲染目标视图和深度模板视图使用不同的多重采样设置:渲染目标使用 4 个样本,而深度模板仅使用 1 个样本。为了让它们一起工作,它们的尺寸和多重采样设置必须完全相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Direct3D 11深度缓冲导致黑屏 - Direct3D 11 depth buffer result in black screen Direct3D 11深度模具/ Alpha混合问题 - Direct3D 11 depth stencil / alpha blending issue Direct3D 11:如何访问CPU侧内存中的多维数据集映射面(ID3D11DeviceContext :: Map是否可与子资源一起使用?)? - Direct3D 11: How to access cube map faces in memory on the CPU side (should ID3D11DeviceContext::Map work with subresources?)? 我需要对Direct3D 11(C ++)中的深度/模板缓冲区的概念进行一些说明 - I need some clarification with the concept of depth/stencil buffers in direct3D 11 (c++) Direct2D可以实际使用direct3D 11设备吗? - Can Direct2D actually work with a direct3D 11 device? 为什么我的纹理不适用? (Direct3D,模式XYZRHW) - Why does my texture not apply? (Direct3D, mode XYZRHW) Direct3D 11 - 绘制三角形 - Direct3D 11 - Drawing a Triangle Direct2D深度缓冲区 - Direct2D Depth Buffer 在 Direct3D 11 中,如何更新附加到精灵的顶点缓冲区或常量缓冲区以使其在屏幕上平滑移动? - How do you update the vertex buffer or constant buffer attached to a sprite to move it smoothly across the screen in Direct3D 11? (C++) Direct3D 11 Draw() 函数不起作用,尽管检查了所有 HRESULT - (C++) Direct3D 11 Draw() function doesn't work, despite checking all HRESULTs
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM