问题
I'm using the SpriteFont/SpriteBatch classes to render text onto my game because quite frankly, i am tired of using Direct2D and DirectWrite... But everytime I draw text using SpriteFont, I get the text written on the screen, but it is written on a black background... The black background blocks the entire scene of my game.. is there any way to remove the black background and only keep the text?
Down below is my implementation of SpriteFont..
void RenderText(int FPS)
{
std::unique_ptr<DirectX::SpriteFont> Sprite_Font(new DirectX::SpriteFont(device, L"myfile.spritefont"));
std::unique_ptr<DirectX::SpriteBatch> Sprite_Batch(new DirectX::SpriteBatch(DevContext));
Sprite_Batch->Begin();
Sprite_Font->DrawString(Sprite_Batch.get(), L"FPS: ", DirectX::XMFLOAT2(200,200));
Sprite_Batch->End();
}
It seems to me that the black background is drawn because of the values that I specified in the function ClearRenderTargetView()
.
float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
DevContext->ClearRenderTargetView(RenderTarget, BackgroundColor); //This is where the black background gets drawn over my entire scene
Everytime i change BackgroundColor[4]
to different values, the background color changes as well, respectably. How can I remove the black background from my game and only include the text?
Here is my entire code.
#include <Windows.h>
#include <SpriteFont.h>
#include <SpriteBatch.h>
#include <d3dcompiler.h>
#include <SimpleMath.h>
#pragma comment (lib, "dinput8.lib")
#pragma comment (lib, "D3D11.lib")
#pragma comment (lib, "d3dcompiler.lib")
LRESULT CALLBACK WindowProcedure(HWND, unsigned int, WPARAM, LPARAM);
void Create_Window(HINSTANCE&);
void Initialize_Direct3D11(HINSTANCE);
void Initialize_Rendering_Pipeline();
void Initialize_Sprites();
void Render_Frame();
void Render_Text();
void Create_Vertex_Buffer_for_triangle();
HWND MainWindow;
IDXGISwapChain * SwapChain;
ID3D11Device * device;
ID3D11DeviceContext * DevContext;
ID3D11RenderTargetView * RenderTarget;
ID3D11Buffer * VertexBuffer;
ID3D10Blob * VertexShader;
ID3D10Blob * PixelShader;
ID3D11VertexShader * VS;
ID3D11PixelShader * PS;
ID3D11InputLayout * inputLayout;
std::unique_ptr<DirectX::SpriteFont> Sprite_Font;
std::unique_ptr<DirectX::SpriteBatch> Sprite_Batch;
DirectX::SimpleMath::Vector2 m_fontPos;
const wchar_t* output = L"Hello World";
struct Vertex_Buffer
{
float Positions[3];
Vertex_Buffer(float x, float y, float z)
{
Positions[0] = x;
Positions[1] = y;
Positions[2] = z;
};
};
int WINAPI WinMain(HINSTANCE CurrentInstance, HINSTANCE PrevInstance, LPSTR ignore, int WindowShow)
{
MSG message;
HRESULT status;
Create_Window(CurrentInstance);
Initialize_Direct3D11(CurrentInstance);
Initialize_Sprites();
Initialize_Rendering_Pipeline();
Create_Vertex_Buffer_for_triangle();
while (true)
{
if (PeekMessage(&message, MainWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
Render_Frame();
Render_Text();
SwapChain->Present(0, 0);
}
}
}
void Initialize_Sprites()
{
Sprite_Font.reset(new DirectX::SpriteFont(device, L"myfile.spritefont"));
Sprite_Batch.reset(new DirectX::SpriteBatch(DevContext));
m_fontPos.x = 200;
m_fontPos.y = 200;
}
void Create_Window(HINSTANCE &CurrentInstance)
{
WNDCLASSEX windowclass;
ZeroMemory(&windowclass, sizeof(WNDCLASSEX));
windowclass.cbSize = sizeof(WNDCLASSEX);
windowclass.lpszClassName = L"Window Class";
windowclass.hInstance = CurrentInstance;
windowclass.lpfnWndProc = WindowProcedure;
windowclass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
windowclass.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&windowclass);
MainWindow = CreateWindowEx(
0,
L"Window Class",
L"The Empire of Anatoria",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
CurrentInstance,
NULL
);
ShowWindow(MainWindow, SW_SHOW);
}
void Render_Text()
{
DirectX::SimpleMath::Vector2 origin = Sprite_Font->MeasureString(output);
Sprite_Batch->Begin();
Sprite_Font->DrawString(Sprite_Batch.get(), output,
m_fontPos, DirectX::Colors::White, 0.f, origin);
Sprite_Batch->End();
}
void Initialize_Direct3D11(HINSTANCE instance)
{
DXGI_MODE_DESC BackBufferDesc;
DXGI_SWAP_CHAIN_DESC SwapChainDesc;
ZeroMemory(&BackBufferDesc, sizeof(DXGI_MODE_DESC));
BackBufferDesc.Width = 400;
BackBufferDesc.Height = 400;
BackBufferDesc.RefreshRate.Numerator = 60;
BackBufferDesc.RefreshRate.Denominator = 1;
BackBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ZeroMemory(&SwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
SwapChainDesc.BufferDesc = BackBufferDesc;
SwapChainDesc.BufferCount = 1;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SampleDesc.Quality = 0;
SwapChainDesc.OutputWindow = MainWindow;
SwapChainDesc.Windowed = TRUE;
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&SwapChainDesc,
&SwapChain,
&device,
NULL,
&DevContext
);
ID3D11Texture2D * BackBuffer;
SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);
device->CreateRenderTargetView(BackBuffer, NULL, &RenderTarget);
DevContext->OMSetRenderTargets(
1,
&RenderTarget,
NULL
);
BackBuffer->Release();
DevContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
void Initialize_Rendering_Pipeline()
{
D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "main", "vs_5_0", 0, 0, &VertexShader, 0);
D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "Pixel_Shader", "ps_5_0", 0, 0, &PixelShader, 0);
device->CreateVertexShader(VertexShader->GetBufferPointer(), VertexShader->GetBufferSize(), NULL, &VS);
device->CreatePixelShader(PixelShader->GetBufferPointer(), PixelShader->GetBufferSize(), NULL, &PS);
DevContext->VSSetShader(VS, 0, 0);
DevContext->PSSetShader(PS, 0, 0);
D3D11_VIEWPORT Raster;
ZeroMemory(&Raster, sizeof(D3D11_VIEWPORT));
Raster.MinDepth = 0.0f;
Raster.MaxDepth = 1.0f;
Raster.Width = 400;
Raster.Height = 400;
DevContext->RSSetViewports(1, &Raster);
D3D11_INPUT_ELEMENT_DESC InputLayout[1];
ZeroMemory(&InputLayout[0], sizeof(D3D11_INPUT_ELEMENT_DESC));
InputLayout[0].SemanticName = "POSITION";
InputLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
InputLayout[0].InputSlot = 0;
InputLayout[0].AlignedByteOffset = 0;
InputLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
device->CreateInputLayout(
InputLayout,
1,
VertexShader->GetBufferPointer(),
VertexShader->GetBufferSize(),
&inputLayout
);
DevContext->IASetInputLayout(inputLayout);
}
void Render_Frame()
{
float BackgroundColor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
DevContext->ClearRenderTargetView(RenderTarget, BackgroundColor);
DevContext->Draw(3, 0);
}
void Create_Vertex_Buffer_for_triangle()
{
D3D11_BUFFER_DESC VertexBufferDesc;
D3D11_SUBRESOURCE_DATA VertexData;
UINT stride = sizeof(Vertex_Buffer);
UINT offset = 0;
ZeroMemory(&VertexBufferDesc, sizeof(D3D11_BUFFER_DESC));
VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
VertexBufferDesc.CPUAccessFlags = 0;
VertexBufferDesc.ByteWidth = sizeof(Vertex_Buffer) * 3;
Vertex_Buffer VerticesData[] =
{
Vertex_Buffer(0.0f, 0.5f, 0.5f),
Vertex_Buffer(0.5f, -0.5f, 0.5f),
Vertex_Buffer(-0.5f, -0.5f, 0.5f)
};
ZeroMemory(&VertexData, sizeof(D3D11_SUBRESOURCE_DATA));
VertexData.pSysMem = VerticesData;
device->CreateBuffer(
&VertexBufferDesc,
&VertexData,
&VertexBuffer);
DevContext->IASetVertexBuffers(
0,
1,
&VertexBuffer,
&stride,
&offset
);
}
LRESULT CALLBACK WindowProcedure(HWND handle, unsigned int message, WPARAM ignore1, LPARAM ignore2)
{
switch (message)
{
case WM_CREATE:
return 0;
case WM_CLOSE:
DestroyWindow(handle);
return 0;
default:
return DefWindowProc(handle, message, ignore1, ignore2);
}
}
Here is the VertexShader.hlsl file
float4 main( float4 pos : POSITION ) : SV_POSITION
{
return pos;
}
float4 Pixel_Shader() : SV_TARGET
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
回答1:
First, if your code snippet is accurate, you should not be creating the SpriteFont
and SpriteBatch
instance every frame. You only have to create them when the device changes.
By default, SpriteFont
is drawing using pre-multiplied alpha blending modes, so if you are getting a fully "background color" image then something else is amiss in your pipeline state. It is likely that you are leaving some state in effect in the rendering between the clear and RenderText
that is affecting the SpriteBatch
renderer that you should reset.
It might also be the color you are using for the background clear which has the alpha set to 0 rather than 1. Try using:
float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
Try working through a few of the DirectX Tool Kit tutorials to make sure things are working in isolation and so you understand how the classes work, specifically Drawing text.
回答2:
You and me have the same problem with SpriteFont
. We forgot to reset the VertexBuffer
s and all other rendering states after the call to SpriteFont
. See my post and the solution from Chuck Walbourn: DirectX::SpriteFont/SpriteBatch prevents 3D scene from drawing.
To quote Chuck:
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.
See my question for additional links providing more information.
来源:https://stackoverflow.com/questions/33860576/problems-when-drawing-text-using-the-spritefont-class