DX11 三角形列表根本不渲染

DX11 triangle list is not rendering at all

我将 4 个顶点的列表加载到顶点缓冲区中,并将索引加载到索引缓冲区中。

我遇到的问题是,虽然 LineList 渲染模式显示四边形很好(见下文),但 TriangleList 什么也没显示(见下文)

void BLX::Model::load(std::filesystem::path path, Model* model, ID3D11Device* d3dDevice, ID3D11DeviceContext* d3dContext)
{
    // tmp: just making a quad
    float num = 0.5f;
    std::vector<BLX::Vertex> vertices = {
        BLX::Vertex { DirectX::XMFLOAT3(-num, -num, 0.0f), DirectX::XMFLOAT3(0.0f, 0.0f, 0.5f), },  // 0 = TL
        BLX::Vertex { DirectX::XMFLOAT3(num, -num, 0.0f), DirectX::XMFLOAT3(0.0f, 0.5f, 0.0f), },   // 1 = TR
        BLX::Vertex { DirectX::XMFLOAT3(num, num, 0.0f), DirectX::XMFLOAT3(0.5f, 0.0f, 0.0f), }, // 2 = BR
        BLX::Vertex { DirectX::XMFLOAT3(-num, num, 0.0f), DirectX::XMFLOAT3(0.5f, 0.5f, 0.0f), },  // 3 = BL
    };

    // line list
    //std::vector<unsigned int> indices = { 0, 1, 1, 2, 2, 3, 3, 0 };

    // triangle list
    std::vector<unsigned int> indices = { 0, 1, 3, 3, 1, 2 };

    model->vertexCount = vertices.size();
    model->indexCount = indices.size();

    // Vertex Buffer

    D3D11_BUFFER_DESC vbd = {};
    vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vbd.Usage = D3D11_USAGE_DEFAULT;
    vbd.CPUAccessFlags = 0u;
    vbd.MiscFlags = 0u;
    vbd.ByteWidth = sizeof(BLX::Vertex) * model->vertexCount;

    vbd.StructureByteStride = sizeof(BLX::Vertex);

    D3D11_SUBRESOURCE_DATA vsd = {};
    vsd.pSysMem = &vertices[0];
    vsd.SysMemPitch = 0;
    vsd.SysMemSlicePitch = 0;

    d3dDevice->CreateBuffer(&vbd, &vsd, &model->vertexBuffer);

    /// Index Buffer
    
    D3D11_BUFFER_DESC ibd = {};
    ibd.Usage = D3D11_USAGE_DEFAULT;
    ibd.ByteWidth = sizeof(unsigned int) * model->indexCount;
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA isd = {};
    isd.pSysMem = &indices[0];
    isd.SysMemPitch = 0;
    isd.SysMemSlicePitch = 0;

    d3dDevice->CreateBuffer(&ibd, &isd, &model->indexBuffer);


    // IA = Input Assembly

    // pixel shader
    D3DReadFileToBlob(L"PixelShader2.cso", &model->pBlob);
    d3dDevice->CreatePixelShader(model->pBlob->GetBufferPointer(), model->pBlob->GetBufferSize(), nullptr, &model->pPixelShader);

    // Vertex Shader
    D3DReadFileToBlob(L"VertexShader2.cso", &model->pBlob);
    d3dDevice->CreateVertexShader(model->pBlob->GetBufferPointer(), model->pBlob->GetBufferSize(), nullptr, &model->pVertexShader);

    const D3D11_INPUT_ELEMENT_DESC ied[] =
    {
        // "Position" correcponds to Vertex Shader Semantic Name
                    // semantic index
                        // data type format
                                                  // Input slot
                                                     // Aligned byte offset
                                                        // Input slot class
                                                                                     // Instance data step rate
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
    // needs vertex shader blob
    d3dDevice->CreateInputLayout(ied, ARRAYSIZE(ied), model->pBlob->GetBufferPointer(), model->pBlob->GetBufferSize(), &model->pInputLayout);
}

void BLX::Model::render(ID3D11Device* d3dDevice, ID3D11DeviceContext* d3dContext, D3D11_VIEWPORT * vp)
{
    const UINT stride = sizeof(Vertex);
    const UINT offset[] = { 0u, 0u };

    d3dContext->IASetVertexBuffers(0u, 1u, vertexBuffer.GetAddressOf(), &stride, &offset[0]);
    d3dContext->IASetIndexBuffer(*indexBuffer.GetAddressOf(), DXGI_FORMAT_R32_UINT, offset[1]);

    d3dContext->PSSetShader(pPixelShader.Get(), nullptr, 0u);
    d3dContext->VSSetShader(pVertexShader.Get(), nullptr, 0u);

    d3dContext->IASetInputLayout(pInputLayout.Get());

    d3dContext->RSSetViewports(1u, vp);

    //d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
    d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    d3dContext->DrawIndexed(indexCount, 0, 0);
}

使用 LineList 索引和拓扑时:

使用 TriangleList 索引和拓扑时:

但是当我这样做的时候:

    // tmp: just making a quad
    float num = 0.5f;
    std::vector<BLX::Vertex> vertices = {
        BLX::Vertex { DirectX::XMFLOAT3(0.0f, num, 0.0f), DirectX::XMFLOAT3(0.0f, 0.0f, 0.5f), },
        BLX::Vertex { DirectX::XMFLOAT3(num, -num, 0.0f), DirectX::XMFLOAT3(0.0f, 0.5f, 0.0f), },
        BLX::Vertex { DirectX::XMFLOAT3(-num, -num, 0.0f), DirectX::XMFLOAT3(0.5f, 0.0f, 0.0f), },
    };

    // triangle list
    std::vector<unsigned int> indices = { 0, 1, 2 };

(其他一切完全相同)我得到了这个:

只是很好奇在尝试渲染两个三角形以组成四边形时我没有看到或得到什么

你的两个网格,三角形和四边形,具有相反的三角形缠绕顺序。方法如下。

By default,D3D11 使用 CullMode=Back 和 FrontCounterClockwise=FALSE。 这意味着它只渲染正面,正面定义为“当顶点为counter-clockwise”时。

从上图可以看出,你的三角形确实有 counter-clockwise 顺序,但是你的四边形的两个三角形都是顺时针的,GPU 将它们视为背面并跳过两者。

您有多种修复方法,以下任何一种都可以。

  1. 重新排序顶点缓冲区中的顶点。
  2. 将索引缓冲区中的三角形翻转为{ 0, 3, 1, 1, 3, 2 }
  3. 更改光栅器状态以禁用背面剔除,CullMode=D3D11_CULL_NONE
  4. 改变光栅器状态以切换正面缠绕方向,FrontCounterClockwise=TRUE
  5. 更改传递给顶点着色器的矩阵以包含镜像组件,例如scale with vector [ -1, 1, 1 ] 表示翻转 X 的镜像变换,这将翻转整个网格的缠绕顺序。

您的矩形具有按顺时针方式组织的索引,这些索引由默认光栅化器剔除(因为您没有指定它会剔除顺时针图元)

你的三角形顶点顺序是逆时针的,所以图元没有被剔除。

解决,两种方案:

  • 更改您的指数顺序:

      std::vector<unsigned int> indices = { 0, 3, 1, 3, 2, 1 };
    
  • 在光栅器状态下禁用剔除:

先创建一个Rasterizer Description

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;

然后使用您的设备创建光栅器状态:

   ID3D11RasterizerState* raster_state;
   HRESULT hr =d3dDevice->CreateRasterizerState(&raster_desc, &raster_state);

在抽奖之前,将您的光栅器状态分配给您的上下文:

   d3dContext->RSSetState(raster_state);