DirectX::SpriteFont/SpriteBatch 阻止绘制 3D 场景 [英] DirectX::SpriteFont/SpriteBatch prevents 3D scene from drawing

查看:33
本文介绍了DirectX::SpriteFont/SpriteBatch 阻止绘制 3D 场景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 DirectX::SpriteFont/DirectX::SpriteBatch(来自 DirectXTK;与此处讨论的问题完全相同:使用SpriteFont类绘制文本时的问题).

void DrawScene(void){HRESULT 小时;float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);XMVECTOR pos = XMLoadFloat3(&g_camera._pos);XMVECTOR 目标 = XMLoadFloat3(&g_camera._target);XMVECTOR up = XMLoadFloat3(&g_camera._up);XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));XMMATRIX wvp = worldBox2 * cameraView * cameraProj;XMMATRIX transposeWvp = XMMatrixTranspose(wvp);XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);//盒子g_pDeviceContext->DrawIndexed(36, 0, 0);wchar_t 缓冲区[32];swprintf_s(buffer, 32, L"%.2f", g_fps._fps);//g_pSp​​riteBatch->Begin();//g_pSp​​riteFont->DrawString(g_pSp​​riteBatch, buffer, XMFLOAT2(30, 30));//g_pSp​​riteBatch->End();//将后台缓冲区显示在屏幕上hr = g_pSwapChain->Present(0, 0);如果(失败(小时)){ErrorBoxW(L"不能没有错误出现.");}}

如果没有调用 SpriteBatch::Begin()SpriteFont::DrawStringSpriteBatch::End(),你会看到一个带纹理的立方体在空间中旋转(笼子).调用上述函数后,您只会在左上角看到每秒帧数,而看不到旋转立方体.

我遵循了 Chuck Walbourn 在 github DirectXTK 上的教程,并结合了使用 SpriteFont 绘制字符串和渲染原始 3D 对象(一个简单的三角形)的 2 个教程.在这个例子中,我将看到测试字符串绘制在三角形上.但是我不明白为什么我的示例中的旋转立方体在使用 DirectXTK 的 SpriteFont 类绘制文本字符串时不可见,我什至找不到根本原因.

像素着色器文件(PixelShader.hlsl):

struct VS_OUTPUT{float4 位置:SV_POSITION;float4 颜色:颜色;float2 TexCoord : TEXCOORD;};Texture2D ObjTexture;SamplerState ObjSamplerState;float4 PS(VS_OUTPUT 输入):SV_TARGET{float4 漫反射 = ObjTexture.Sample(ObjSamplerState, input.TexCoord);剪辑(diffuse.a - 0.25);返回扩散;}

顶点着色器文件(VertexShader.hlsl):

cbuffer constantBufferPerObject{float4x4 WVP;浮动颜色调整;整数模式;内垫[2];};结构VS_OUTPUT{float4 位置:SV_POSITION;float4 颜色:颜色;float2 TexCoord : TEXCOORD;};VS_OUTPUT VS( float4 pos : POSITION, float4 color : COLOR_ZERO, float4 color2 : COLOR_ONE, float2 texCoord : TEXCOORD ){VS_OUTPUT 输出;浮动4温度;output.Pos = mul(pos, WVP);温度 = 颜色;output.Color.r = temp.r * color2.r * (1.0f - ColorAdjust);output.Color.g = temp.g * color2.g * (1.0f - ColorAdjust);output.Color.b = temp.b * color2.b * (1.0f - ColorAdjust);output.Color.a = color.a * color2.a;输出.TexCoord = texCoord;返回输出;}

重现问题:我正在使用 Visual Studio 2015 社区版.我在我的项目中添加了 DirectXTK (.lib) 和 DirectXTex (WICTextureLoader .cpp/.h, DDSTextureLoader .cpp/.h, .lib).立方体的图像是带有 alpha 的 .png.

注意:我创建了这个重复问题,以

<块引用>

避免 ...寻求帮助、澄清或回应其他答案.

关于另一个问题.

解决方案

首先,由于您使用的是 DirectXTK,因此您不需要 DirectXTex.DirectXTex 用于纹理处理工具,而 DirectXTK 纹理加载器更适合在应用程序中使用.请参阅此博客发布.

第二,不要使用古老的timeGetTime 函数.您可以使用 GetTickCount,尽管 GetTickCount64 更好,因为它避免了溢出问题.然而,对于帧时序来说,这些还不够精确.你应该看看 DirectX Tool Kit 教程中使用的 StepTimer.h.>

第三,您应该考虑使用 Microsoft::WRL::ComPtr 而不是所有的 SAFE_RELEASE 宏内容.有关详细信息,请参阅此页面.

<块引用>

您的代码也包括 xinput.h.您应该考虑使用 DirectX Tool Kit 的 GamePad 而不是它有很多好处.如果不出意外,它使用 XInput 的能力比您想象的要强.

综上所述,您的问题非常简单:您在 InitScene 中为您的场景设置了渲染状态,但绘制了任何内容else 改变状态,这正是 SpriteBatch 所做的.我在 wiki 上记录了 DirectX Toolkit 中每个对象操作的渲染状态.

您需要设置您的 Draw 需要每一帧的所有状态,如果您进行多次绘图,则不要假设它是永远设置的.

void DrawScene(void){HRESULT 小时;float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);//>>>>这些是从上面的初始场景移过来的!//设置顶点和像素着色器g_pDeviceContext->VSSetShader(g_pVertexShader, 0, 0);g_pDeviceContext->PSSetShader(g_pPixelShader, 0, 0);//设置顶点缓冲区UINT 步幅 = sizeof(SimpleVertex);UINT 偏移量 = 0;g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pTriangleVertexBuffer, &stride, &offset);g_pDeviceContext->IASetIndexBuffer(g_pSquareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);//设置输入布局g_pDeviceContext->IASetInputLayout(g_pVertexLayout);//设置原始拓扑g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);//每个三角形 3 个顶点//g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);//每个点 1 个顶点//g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);//每行 2 个顶点//创建视口g_pDeviceContext->RSSetState(g_pNoCullSolid);//这些是从上面的初始场景移过来的!<<<<XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);XMVECTOR pos = XMLoadFloat3(&g_camera._pos);XMVECTOR 目标 = XMLoadFloat3(&g_camera._target);XMVECTOR up = XMLoadFloat3(&g_camera._up);XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));XMMATRIX wvp = worldBox2 * cameraView * cameraProj;XMMATRIX transposeWvp = XMMatrixTranspose(wvp);XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);//盒子g_pDeviceContext->DrawIndexed(36, 0, 0);wchar_t 缓冲区[32];swprintf_s(buffer, 32, L"%.2f", g_fps._fps);g_pSp​​riteBatch->Begin();g_pSp​​riteFont->DrawString(g_pSp​​riteBatch, buffer, XMFLOAT2(30, 30));g_pSp​​riteBatch->End();//将后台缓冲区显示在屏幕上hr = g_pSwapChain->Present(0, 0);//>>>>此行为意味着如果您点击 DEVICE_REMOVED 或 DEVICE_RESET,应用程序会崩溃.如果(失败(小时)){ErrorBoxW(L"不能没有错误出现.");}}

您通常可以为视口状态设置它并忘记它"RSSetViewports,它也隐式设置剪刀状态,但更好的用法是在每帧开始时设置它您最初的Clear.这是我在 Direct3D 游戏模板中使用的模式.

I have a problem using DirectX::SpriteFont/DirectX::SpriteBatch (from DirectXTK; exactly the same problem as discussed here: Problems when drawing text using the SpriteFont class).

void DrawScene(void)
{
    HRESULT hr;

    float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };

    g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);
    g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);
    XMVECTOR pos = XMLoadFloat3(&g_camera._pos);
    XMVECTOR target = XMLoadFloat3(&g_camera._target);
    XMVECTOR up = XMLoadFloat3(&g_camera._up);
    XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);
    XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));
    XMMATRIX wvp = worldBox2 * cameraView * cameraProj;
    XMMATRIX transposeWvp = XMMatrixTranspose(wvp);
    XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);
    g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);
    g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);

    g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);
    g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);

    // box
    g_pDeviceContext->DrawIndexed(36, 0, 0);

    wchar_t buffer[32];
    swprintf_s(buffer, 32, L"%.2f", g_fps._fps);

    //g_pSpriteBatch->Begin();
    //g_pSpriteFont->DrawString(g_pSpriteBatch, buffer, XMFLOAT2(30, 30));
    //g_pSpriteBatch->End();

    // Present the backbuffer to the screen
    hr = g_pSwapChain->Present(0, 0);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot present without error.");
    }
}

Without the calls to SpriteBatch::Begin(), SpriteFont::DrawString and SpriteBatch::End() you will see a textured cube rotating through space (a cage). With the calls to the described functions, you will only see the frames per second in the upper left corner, but no rotating cube.

I followed the tutorials from Chuck Walbourn on github DirectXTK and combined the 2 tutorials Draw String using SpriteFont and rendering a primitive 3D object (a simple triangle). In this example I will see the test string drawing over the triangle. But I do not understand why the rotating cube from my example is not visible while drawing a text string using SpriteFont class of DirectXTK and I cannot even find the root cause.

Pixel shader file (PixelShader.hlsl):

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

Texture2D ObjTexture;
SamplerState ObjSamplerState;

float4 PS( VS_OUTPUT input ) : SV_TARGET
{
    float4 diffuse = ObjTexture.Sample(ObjSamplerState, input.TexCoord);
    clip(diffuse.a - 0.25);
    return diffuse;
}

Vertex shader file (VertexShader.hlsl):

cbuffer constantBufferPerObject
{
    float4x4 WVP;
    float ColorAdjust;
    int Mode;
    int Pad[2];
};

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

VS_OUTPUT VS( float4 pos : POSITION, float4 color : COLOR_ZERO, float4 color2 : COLOR_ONE, float2 texCoord : TEXCOORD )
{
    VS_OUTPUT output;
    float4 temp;
    output.Pos = mul(pos, WVP);  
    temp = color;
    output.Color.r = temp.r * color2.r * (1.0f - ColorAdjust);
    output.Color.g = temp.g * color2.g * (1.0f - ColorAdjust);
    output.Color.b = temp.b * color2.b * (1.0f - ColorAdjust);
    output.Color.a = color.a * color2.a;
    output.TexCoord = texCoord;
    return output;
}

To reproduce the issue: I am working with Visual Studio 2015 Community Edition. I added DirectXTK (.lib) and DirectXTex (WICTextureLoader .cpp/.h, DDSTextureLoader .cpp/.h, .lib) to my project. Image for cube is .png with alpha.

Note: I created this duplicated question, to

avoid ... Asking for help, clarification, or responding to other answers.

on the other question.

解决方案

First, as you are using DirectXTK, you don't need DirectXTex. DirectXTex is intended for texture processing tools, while DirectXTK texture loaders are more suited to use in applications. See this blog post.

Second, don't use the ancient timeGetTime function. You can use GetTickCount, although GetTickCount64 is better as it avoids overflow problems. For frame timing, however, these are not really precise enough. You should take a look at the StepTimer.h used in the DirectX Tool Kit tutorials.

Third, you should look at using Microsoft::WRL::ComPtr rather than all the SAFE_RELEASE macro stuff. See this page for details.

Your code was including xinput.h as well. You should take a look at using DirectX Tool Kit's GamePad instead which has a number of benefits. If nothing else, it uses XInput more robustly than you likely would.

With all that said, your problem is quite simple: You set the render state up for your scene in InitScene, but drawing anything else changes the state which is exactly what SpriteBatch does. I document which render states each object in DirectX Toolkit manipulates on the wiki.

You need to set all the state your Draw requires each frame, not assume it is set forever, if you do more than a single draw.

void DrawScene(void)
{
    HRESULT hr;

    float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };

    g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);
    g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

//>>>> THESE WERE MOVED FROM INITSCENE ABOVE!
    // Set Vertex and Pixel Shaders
    g_pDeviceContext->VSSetShader(g_pVertexShader, 0, 0);
    g_pDeviceContext->PSSetShader(g_pPixelShader, 0, 0);

    // Set the vertex buffer
    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;
    g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pTriangleVertexBuffer, &stride, &offset);

    g_pDeviceContext->IASetIndexBuffer(g_pSquareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // Set the Input Layout
    g_pDeviceContext->IASetInputLayout(g_pVertexLayout);

    // Set Primitive Topology
    g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 3 vertices per triangle
                                                                                     //g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); // 1 vertex per point
                                                                                     //g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); // 2 vertices per line

                                                                                     // Create the Viewport

    g_pDeviceContext->RSSetState(g_pNoCullSolid);
//THESE WERE MOVED FROM INITSCENE ABOVE! <<<<

    XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);
    XMVECTOR pos = XMLoadFloat3(&g_camera._pos);
    XMVECTOR target = XMLoadFloat3(&g_camera._target);
    XMVECTOR up = XMLoadFloat3(&g_camera._up);
    XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);
    XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));
    XMMATRIX wvp = worldBox2 * cameraView * cameraProj;
    XMMATRIX transposeWvp = XMMatrixTranspose(wvp);
    XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);
    g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);
    g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);

    g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);
    g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);

    // box
    g_pDeviceContext->DrawIndexed(36, 0, 0);

    wchar_t buffer[32];
    swprintf_s(buffer, 32, L"%.2f", g_fps._fps);

    g_pSpriteBatch->Begin();
    g_pSpriteFont->DrawString(g_pSpriteBatch, buffer, XMFLOAT2(30, 30));
    g_pSpriteBatch->End();

    // Present the backbuffer to the screen
    hr = g_pSwapChain->Present(0, 0);
//>>>> This behavior means the app crashes if you hit a DEVICE_REMOVED or DEVICE_RESET.
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot present without error.");
    }
}

You can generally 'set it and forget it' for the viewport state RSSetViewports which also implicitly sets the scissors state, but a better usage is to set it at the start of each frame when you do your initial Clear. This is the pattern I use in the Direct3D Game Templates.

这篇关于DirectX::SpriteFont/SpriteBatch 阻止绘制 3D 场景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆