Проблемы при рисовании текста с использованием класса SpriteFont

Я использую классы SpriteFont/SpriteBatch для рендеринга текста в своей игре, потому что, честно говоря, я устал от использования Direct2D и DirectWrite... Но каждый раз, когда я рисую текст с помощью SpriteFont, я получаю текст, написанный на экране, но он написано на черном фоне... Черный фон закрывает всю сцену в моей игре.. есть ли способ убрать черный фон и оставить только текст?

Ниже приведена моя реализация 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();


}

Мне кажется, что черный фон рисуется из-за значений, которые я указал в функции 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

Каждый раз, когда я меняю BackgroundColor[4] на разные значения, цвет фона также меняется, прилично. Как я могу удалить черный фон из моей игры и оставить только текст?

Вот весь мой код.

#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);
}


}

Вот файл VertexShader.hlsl

float4 main( float4 pos : POSITION ) : SV_POSITION
{
return pos;
}

float4 Pixel_Shader() : SV_TARGET
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}

person Soon_to_be_code_master    schedule 22.11.2015    source источник
comment
Попробуйте использовать вызов Begin для пакета спрайтов с AlphaBlend для состояния наложения (или, возможно, NonPremultiplied). Просто предположение - это за пределами моей области, но я копался в документах, пытаясь найти режим прозрачного рисования.   -  person    schedule 23.11.2015
comment
Я уже пытался установить состояние наложения, чтобы сделать фон прозрачным, но это все равно не работает. Фон по-прежнему блокирует всю сцену   -  person Soon_to_be_code_master    schedule 23.11.2015
comment
Любые другие рекомендации?   -  person Soon_to_be_code_master    schedule 23.11.2015
comment
Извинения - это было мое единственное. Я никогда не работал с этим API, но я надеюсь, что кто-то, у кого есть, заметит эту тему и присоединится.   -  person    schedule 23.11.2015
comment
Откуда взялся файл VertexShader.hlsl? Похоже, что в нем есть и ваш вершинный, и пиксельный шейдер, хотя это может быть и не так, поскольку у вас нет проверки ошибок при вызове D3DCompileFromFile   -  person Chuck Walbourn    schedule 25.11.2015
comment
Я включил VertexShader.hlsl в исходный пост. И да, вы правы, я проверю все функции на наличие ошибок.   -  person Soon_to_be_code_master    schedule 25.11.2015


Ответы (2)


Во-первых, если ваш фрагмент кода точен, вам не следует создавать экземпляры SpriteFont и SpriteBatch в каждом кадре. Их нужно создавать только при смене устройства.

По умолчанию SpriteFont рисует с использованием предварительно умноженных режимов наложения альфа-канала, поэтому, если вы получаете изображение с полностью «фоновым цветом», значит, что-то еще не так в вашем состоянии конвейера. Вполне вероятно, что вы оставляете какое-то состояние в рендеринге между очисткой и RenderText, которое влияет на рендерер SpriteBatch, который вы должны сбросить.

Это также может быть цвет, который вы используете для очистки фона, у которого альфа установлена ​​на 0, а не на 1. Попробуйте использовать:

float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

Попробуйте поработать с несколькими из набора инструментов DirectX руководства, чтобы убедиться, что все работает изолированно, и чтобы вы понимали, как работают классы, в частности Текст рисования.

person Chuck Walbourn    schedule 23.11.2015
comment
Я пошел к учебникам, и я думаю, что лучше понимаю эти классы. Но у меня есть вопрос, когда я должен reset() экземпляры SpriteBatch и SpriteFont? Должен ли я сбросить их в игровом цикле? - person Soon_to_be_code_master; 24.11.2015
comment
Вам нужно только reset() std::unique_ptr<T> в сценарии "устройство потеряно" (т. е. Present возвращает DXGI_ERROR_DEVICE_REMOVED или DXGI_ERROR_DEVICE_RESET, что означает, что устройство недействительно, и все на основе устройства Direct3D необходимо выбросить и воссоздать с помощью новый экземпляр устройства). Внимательно изучите урок основной игровой цикл. - person Chuck Walbourn; 24.11.2015
comment
Я следовал каждому шагу в учебниках, но черный фон сохраняется. Я даже сделал новое приложение, которое просто рисует красный треугольник, и как только я сделал спрайты, черный фон закрывает треугольник. Я включил код моего нового приложения в свой исходный пост, если у вас есть свободное время, вы можете воспроизвести проблему? - person Soon_to_be_code_master; 25.11.2015
comment
Первое, что вы должны сделать со своим кодом, — это проверить HRESULT возврат всех функций, которые возвращают его: HRESULT hr = /* Direct3D Function */; if (FAILED(hr)) /* error */ В приведенном выше фрагменте кода фактически нет проверки ошибок, поэтому вы не получите уведомление, если что-то пойдет не так. Во-вторых, вам нужно включить устройство отладки Direct3D, передав D3D11_CREATE_DEVICE_DEBUG в качестве четвертого параметра в D3D11CreateDeviceAndSwapChain. См. Отладка Direct3D SDK. Трюки со слоями. - person Chuck Walbourn; 25.11.2015

У нас с вами одна и та же проблема с SpriteFont. Мы забыли сбросить VertexBuffers и все остальные состояния рендеринга после вызова SpriteFont. См. мой пост и решение от Chuck Walbourn: DirectX ::SpriteFont/SpriteBatch предотвращает отрисовку 3D-сцены.

Цитирую Чака:

Вы устанавливаете состояние рендеринга для своей сцены в InitScene, но рисование чего-либо еще изменяет состояние, что и делает SpriteBatch. Я документирую состояние рендеринга каждого объекта в DirectX Toolkit на вики. Вам нужно установить все состояние, которое требует отрисовка для каждого кадра, а не предполагать, что оно установлено навсегда, если вы делаете более одной отрисовки.

См. мой вопрос для дополнительных ссылок, предоставляющих дополнительную информацию.

person wlasar86    schedule 23.02.2016