0

我正在尝试通过使用SpriteFontand在我的 DX11 项目中呈现文本SpriteBatch

在添加代码之前一切正常,但是当未注释代码时,我收到以下错误并且没有任何渲染。

D3D11 ERROR: ID3D11DeviceContext::DrawIndexed: Input Assembler - Vertex Shader linkage error: Signatures between stages are incompatible. Semantic 'TEXCOORD' is defined for mismatched hardware registers between the output stage and input stage. [ EXECUTION ERROR #343: DEVICE_SHADER_LINKAGE_REGISTERINDEX]
D3D11 ERROR: ID3D11DeviceContext::DrawIndexed: Input Assembler - Vertex Shader linkage error: Signatures between stages are incompatible. The input stage requires Semantic/Index (POSITION,0) as input, but it is not provided by the output stage. [ EXECUTION ERROR #342: DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND]
D3D11 ERROR: ID3D11DeviceContext::DrawIndexed: Input Assembler - Vertex Shader linkage error: Signatures between stages are incompatible. The input stage requires Semantic/Index (NORMAL,0) as input, but it is not provided by the output stage. [ EXECUTION ERROR #342: DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND]

我试图更改 DeviceContext & Device,但仍然是同样的错误。

    //Draw Text
    g_spriteBatch = std::make_unique<SpriteBatch>(g_pImmediateContext);
    g_spriteFont = std::make_unique<SpriteFont>(g_pd3dDevice1, L"Data\\game_font.spritefont");

    //Render Text
    g_spriteBatch->Begin();
    //g_spriteFont->DrawString(g_spriteBatch.get(), L"Score: 0", XMFLOAT2(0,0), DirectX::Colors::White);
    g_spriteBatch->End();

我试过使用不同的设备和设备上下文,但仍然是同样的错误。


我一直在尝试许多不同的方法来让这个工作。这就是我的渲染函数目前的样子

更新日期:18/02/2019

void Render() {

    float backgroundColour[] = { 0.0f, 0.1f, 0.5f, 0.0f };
    g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, backgroundColour);
    g_pImmediateContext->ClearDepthStencilView(g_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
    g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    g_pImmediateContext->RSSetState(g_rasterState);
    g_pImmediateContext->OMSetDepthStencilState(g_depthStencilState, 0);
    g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
    g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);

    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;

    g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
    g_pImmediateContext->Draw(3, 0);
    //g_pImmediateContext->DrawIndexed(36, 0, 0);

    //Draw Text
    spriteBatch->Begin();
    spriteFont->DrawString(spriteBatch.get(), L"Test", DirectX::XMFLOAT2(0, 0), DirectX::Colors::White);
    spriteBatch->End();

    //Present our back buffer to the front buffer
    g_pSwapChain->Present(0, NULL);

}

运行项目时,出现以下错误 D3D11 ERROR: ID3D11DeviceContext::IASetVertexBuffers: A Buffer trying to be bound to slot 0 did not have the appropriate bind flag set at creation time to allow the Buffer to be bound as a VertexBuffer. [ STATE_SETTING ERROR #238: IASETVERTEXBUFFERS_INVALIDBUFFER]

这是存储 tri 数据并设置索引/顶点缓冲区的代码

    SimpleVertex vertices[] =
    {           
        SimpleVertex(-0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f),
        SimpleVertex( 0.0f,  0.5f, 1.0f, 1.0f, 0.0f, 0.0f),
        SimpleVertex( 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f),
    };

    D3D11_BUFFER_DESC bd = {};
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( SimpleVertex ) * ARRAYSIZE(vertices);
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = vertices;
    hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
    if (FAILED(hr))
    {
        printf("Failed ro Create Vertex Buffer.");
        return hr;
    }

我已更改D3D11_BIND_INDEX_BUFFERD3D11_BIND_VERTEX_BUFFER并发生相同的错误。

在此之后,还会产生以下警告。

D3D11 WARNING: ID3D11DeviceContext::Draw: Vertex Buffer at the input vertex slot 0 is not big enough for what the Draw*() call expects to traverse. This is OK, as reading off the end of the Buffer is defined to return 0. However the developer probably did not intend to make use of this behavior.  [ EXECUTION WARNING #356: DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL]

D3D11 WARNING: ID3D11DeviceContext::Draw: The size of the Constant Buffer at slot 0 of the Vertex Shader unit is too small (64 bytes provided, 192 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects.  [ EXECUTION WARNING #351: DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL]

D3D11 WARNING: ID3D11DeviceContext::Draw: Input vertex slot 0 has stride 24 which is less than the minimum stride logically expected from the current Input Layout (32 bytes). This is OK, as hardware is perfectly capable of reading overlapping data. However the developer probably did not intend to make use of this behavior.  [ EXECUTION WARNING #355: DEVICE_DRAW_VERTEX_BUFFER_STRIDE_TOO_SMALL]
4

1 回答 1

1

TL;DR:在调用Draw.

具体来说,您忘记设置顶点缓冲区,因为您留下了注释掉的代码:

// >>> Set vertex buffer
//g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);

您的评论包括您得到的调试设备错误,导致您首先将其注释掉。很明显,您的错误实际上是您在CreateBuffer没有设置D3D11_BUFFER_DESC.BindFlagsD3D11_BIND_VERTEX_BUFFER.

在每次调用之前,Draw*您需要设置该抽奖所需的任何状态。

通过调用更改的确切状态SpriteFont::Begin/End记录在wiki上。特别是,它改变了输入布局和顶点着色器。您的“立方体绘图”代码依赖于这些状态在每帧之间保持不变,这实际上只适用于微不足道的情况。

在每个渲染帧开始时,您应该:

  • 清除渲染目标和/或深度模板缓冲区
  • 调用OMSetRenderTargets以设置您的主要渲染目标
  • 调用RSSetViewports以设置您的视口状态

然后在每次调用之前Draw*设置您使用的所有状态。对于简单的 3D 立方体绘图,这至少包括:

  • 渲染目标视图、深度模板视图、视口(在简单的情况下可以在帧开始处设置一次)
  • BlendState、DepthStencilState、RasterizerState
  • 输入布局
  • 任何常量缓冲区、像素着色器、顶点着色器和任何必需的 SamplerState 或着色器资源。

DirectX 工具包包括许多帮助程序,例如和CommonState以便Effects更易于管理,但您仍然必须确保设置了您所依赖的所有状态。

状态管理

状态管理是 Direct3D 编程的基本要求,对性能尤其重要。在您调用的任何给定时间Draw*,需要在渲染管道上设置该绘制所需的所有状态,但您确实希望最大限度地减少更改状态的次数以提高性能。

在DirectX Tool Kit等实用程序库中,实际上存在三种状态管理基本策略:

  1. 捕获并恢复所有状态。这就是ID3DXFont弃用D3DX9库中的旧版 Direct3D 9 时代代码所做的。在 Direct3D 9 中,这最初是通过运行时跟踪当前状态来实现的。专门引入了“PURE”设备来尝试消除这种开销,因此添加了状态块作为尝试使其工作的一种方式。Direct3D 11 中的状态向量也相当大,并且运行时不以同样的方式支持“状态块”。总的来说,这种方法非常易于使用,但速度并不快。

  2. 设置所有需要的状态,之后清除使用的状态。另一种选择是在每次使用任何辅助函数(如 )时设置所有状态SpriteBatch::Begin,然后在调用SpriteBatch::Endclear 时设置它使用的任何状态值。这种方法在概念上也很简单,因为没有挥之不去的副作用,但实际上也很慢,因为有很多额外的调用来设置 null 状态。

  3. 设置所需的状态,让稍后绘制清理状态。这是DirectX Tool Kit使用的选项。我设置了我需要绘制的状态,然后不管它。如果在帧结束之前调用我的代码后还有更多绘图要做,则需要设置它们。在实践中,DirectX Tool Kit中的助手只使用了基本所有绘图通用的标准状态,但如果你不知道这种行为,你肯定会得到一些奇怪的交互。例如,如果您在调用之前设置了几何着色器SpriteBatch,那么调用时会发生奇怪的事情End. 我假设如果您使用的东西超出了通常的 VS/PS 组合,您在调用我的代码之前清除了它。我在 wiki 上记录了每个助手使用的所有状态,实际上这是性能和可预测行为之间的良好平衡,尽管它有时会让人感到困惑。

Direct3D 11 与 Direct3D 12 注意事项

在 Direct3D 11 中,调用时在帧末尾设置的任何状态Present仍会在下一帧开始时设置,因此您会看到一些较早的教程在开始渲染循环之前设置了一次状态并假设保持不变。这不适用于 Direct3D 12,其中状态由Present. 因此,最好养成每帧设置所有状态的习惯。验证您是否正确执行此操作的一种方法是ClearState在每一帧之后立即调用Present,尽管您可能只想在 Debug 构建中执行此操作,因为否则在正确编写的程序中这是浪费时间。

在 Direct3D 11 中,设置视口的调用RSSetViewports也会将剪裁剪裁矩形初始化为相同的值。在 Direct3D 12 中,您需要通过调用显式执行此操作,RSSetScissorRects否则您最终会得到一个 (0,0,0,0) 剪切矩形,它会剪切掉所有内容。

有关这些基本渲染循环的一些示例,请参阅GitHub

于 2019-02-07T17:31:29.670 回答