DirectX::SpriteFont/SpriteBatch предотвращает рисование 3D-сцены

У меня проблема с использованием DirectX::SpriteFont/DirectX::SpriteBatch (из DirectXTK; точно такая же проблема, как обсуждалось здесь: проблемы при рисовании текста с использованием класса SpriteFont).

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.");
    }
}

Без звонков SpriteBatch::Begin(), SpriteFont::DrawString а также SpriteBatch::End() Вы увидите текстурированный куб, вращающийся в пространстве (клетка). При вызовах описанных функций вы будете видеть только кадры в секунду в верхнем левом углу, но без вращающегося куба.

Я следовал учебным пособиям Чака Уолборна на github DirectXTK и соединил 2 урока Draw String, используя SpriteFont и рендеринг примитивного трехмерного объекта (простой треугольник). В этом примере я увижу тестовую строку, рисующую над треугольником. Но я не понимаю, почему вращающийся куб из моего примера не виден при рисовании текстовой строки с помощью SpriteFont класс DirectXTK, и я даже не могу найти основную причину.

Файл пиксельного шейдера (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;
}

Файл вершинного шейдера (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;
}

Чтобы воспроизвести проблему: я работаю с Visual Studio 2015 Community Edition. Я добавил DirectXTK (.lib) и DirectXTex (WICTextureLoader.cpp /.h, DDSTextureLoader.cpp /.h,.lib) к моему проекту. Изображение для куба.png с альфа.

Примечание: я создал этот дублированный вопрос, чтобы

избегать... Обращаться за помощью, разъяснениями или отвечать на другие ответы.

по другому вопросу.

2 ответа

Решение

Во-первых, поскольку вы используете DirectXTK, вам не нужен DirectXTex. DirectXTex предназначен для инструментов обработки текстур, тогда как загрузчики текстур DirectXTK больше подходят для использования в приложениях. Смотрите этот пост в блоге.

Во-вторых, не используйте древние timeGetTime функция. Ты можешь использовать GetTickCount, хотя GetTickCount64 лучше, поскольку это позволяет избежать проблем переполнения. Однако для синхронизации кадров они не совсем точны. Вы должны взглянуть на StepTimer.h, используемый в руководствах по DirectX Tool Kit.

В-третьих, вы должны смотреть на использование Microsoft::WRL::ComPtr а не все SAFE_RELEASE макро вещи. Смотрите эту страницу для деталей.

Ваш код был в том числе xinput.h также. Вам следует взглянуть на использование GamePad DirectX Tool Kit, который имеет ряд преимуществ. Если ничего другого, он использует XInput более надежно, чем вы, вероятно.

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

Вам нужно установить все состояния, которые требуются для каждого рисования в каждом кадре, не предполагайте, что он установлен навсегда, если вы выполняете более одного рисунка.

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.");
    }
}

Обычно вы можете "установить и забыть" для состояния области просмотра RSSetViewports который также неявно устанавливает состояние ножниц, но лучше использовать его в начале каждого кадра, когда вы делаете начальный Clear, Это шаблон, который я использую в шаблонах игр Direct3D.

Вот полный код:

#include <Windows.h>
#include <stdio.h>
#include <Xinput.h>
#include <DirectXMath.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXTex.h>
#include <SpriteFont.h>

#include "DDSTextureLoader.h"
#include "WICTextureLoader.h"

using namespace DirectX;

#define CAMERA_ROTATION_SPEED (110.0f)
#define CAMERA_TARGET_DISTANCE (3.0f)
#define CAMERA_TARGET_VIEW_Y_START (-15.0f)
#define CAMERA_TARGET_VIEW_XZ_START (0.0f)
#define CAMERA_TARGET_START (XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f))
#define CAMERA_UP_START (XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f))
#define CAMERA_POS_START (XMVectorSet(0.0f, 0.0f, 3.0f, 0.0f))

#define PLAYER_MOVEMENT_SPEED (5.0f)

#define SAFE_DELETE(p) if (p) { delete (p); (p) = NULL; }
#define SAFE_RELEASE(p) if (p) { (p)->Release(); (p) = NULL; }

#ifdef _DEBUG
#define ErrorBoxW(msg) MessageBox(NULL, (msg), L"Error", MB_OK | MB_ICONERROR)
#else // _DEBUG
#define ErrorBox(msg)
#endif // _DEBUG

#define NORMALIZE_ANGLE(ang) { while ((ang) > 360.0f) { (ang) -= 360.0f; } while ((ang) < -360.0f) { (ang) += 360.0f; } }
#define LIMIT_ANGLE(ang, val) { if ((ang) > (val)) { (ang) = (val); } if ((ang) < -(val)) { (ang) = -(val); } }
#define CHECK_CHANGE_F(curr, prev, flag) { (flag) = (curr) != (prev); }

typedef struct _Camera
{
    XMFLOAT3 _target;
    XMFLOAT3 _pos;
    XMFLOAT3 _up;
    float _viewRotXZ;
    float _viewRotY;
    XMFLOAT4X4 _cameraProjection;
} Camera;

typedef struct _FPS
{
    _FPS(void)
        : _elapsedTime(0.0f), _frames(0), _fps(0.0f) {}
    void Calc(float timeDelta)
    {
        _elapsedTime += timeDelta;
        _frames++;

        if (_elapsedTime >= 1.0f)
        {
            _fps = (float)_frames / _elapsedTime;

            _elapsedTime = 0.0f;
            _frames = 0;

#ifdef _DEBUG
            wchar_t buffer[32];
            swprintf_s(buffer, 32, L"FPS: %.2f\n", _fps);
            OutputDebugString(buffer);
#endif // _DEBUG
        }
    }

    float _fps;
    float _elapsedTime;
    int _frames;
} FPS;

typedef struct _Player
{
    _Player(void)
        : _moveX(0.0f), _moveY(0.0f), _moveZ(0.0f) {}

    float _moveX;
    float _moveY;
    float _moveZ;
} Player;

using namespace DirectX;

typedef struct _SimpleVertex
{
    _SimpleVertex() {}
    _SimpleVertex(float x, float y, float z, float cr, float cg, float cb, float ca, float cr2, float cg2, float cb2, float ca2, float u, float v)
        : _pos(x, y, z), _color0(cr, cg, cb, ca), _color1(cr2, cg2, cb2, ca2), _tex(u, v) {}

    XMFLOAT3 _pos;
    XMFLOAT4 _color0;
    XMFLOAT4 _color1;
    XMFLOAT2 _tex;
} SimpleVertex;

// sizeof(ConstantBufferPerObject) = 80; multiple of 16
typedef struct _ConstantBufferPerObject
{
    XMFLOAT4X4 _wvp; // sizeof(XMFLOAT4X4) = 64
    float _colorAdjust; // sizeof(float) = 4; 68
    int _mode; // sizeof(int) = 4; 72
    int _pad[2]; // 2 * sizeof(int) = 8; 80
} ConstantBufferPerObject;

LPWSTR const g_windowClassName = L"dx11demo";
LPWSTR const g_windowTitle = L"DirectX11Demo";
HWND g_hwnd = NULL;
HINSTANCE g_hinstance = NULL;
const int g_width = 800;
const int g_height = 600;
IDXGISwapChain *g_pSwapChain = NULL;
ID3D11Device *g_pDevice = NULL;
ID3D11DeviceContext *g_pDeviceContext = NULL;
ID3D11RenderTargetView *g_pRenderTargetView = NULL;
ID3D11Buffer *g_pTriangleVertexBuffer = NULL;
ID3D11Buffer *g_pSquareIndexBuffer = NULL;
ID3D11VertexShader *g_pVertexShader = NULL;
ID3D11PixelShader *g_pPixelShader = NULL;
ID3DBlob *g_pVertexShaderBuffer = NULL;
ID3DBlob *g_pPixelShaderBuffer = NULL;
ID3D11DepthStencilView *g_pDepthStencilView = NULL;
ID3D11Buffer *g_pConstantBufferPerObject = NULL;
ID3D11Texture2D *g_pDepthStencilBuffer = NULL;
ID3D11InputLayout *g_pVertexLayout = NULL;
ID3D11ShaderResourceView *g_pCageTexture = NULL;
ID3D11ShaderResourceView *g_pBrickTexture = NULL;
ID3D11SamplerState *g_pCubeTextureSamplerState = NULL;
bool g_solid = true;
float g_rotBox2 = 0.0f;
ID3D11RasterizerState *g_pNoCullSolid = NULL;
ID3D11RasterizerState *g_pNoCullWireframe = NULL;
ID3D11RasterizerState *g_pCWCullSolid = NULL;
ID3D11RasterizerState *g_pCCWCullSolid = NULL;
ID3D11BlendState *g_pTransparency = NULL;
SpriteBatch *g_pSpriteBatch = NULL;
SpriteFont *g_pSpriteFont = NULL;
D3D11_INPUT_ELEMENT_DESC g_layout_a[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR_ZERO", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR_ONE", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT g_numElements = ARRAYSIZE(g_layout_a);
bool g_isMoving = true;
ConstantBufferPerObject g_constantBufferPerObject;
bool g_enableDraw = true;
Player g_player;
Camera g_camera;
FPS g_fps;

void CleanUp(void);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
bool InitD3D11(void);
bool InitScene(void);
void DrawScene(void);
void UpdateScene(float);

void UpdateScene(float timeDelta)
{
    g_rotBox2 += 20.0f * timeDelta;
    NORMALIZE_ANGLE(g_rotBox2);
}

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.");
    }
}

bool InitScene(void)
{
    HRESULT hr;
    ID3DBlob *pErrorBlob = NULL;
    UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
    flags |= D3DCOMPILE_DEBUG;
#endif // _DEBUG

    const D3D_SHADER_MACRO defines_a[] =
    {
        { NULL, NULL }
    };

    // Compile Shaders from shader file
    // https://msdn.microsoft.com/de-de/library/windows/desktop/hh968107(v=vs.85).aspx
    hr = D3DCompileFromFile(L"VertexShader.hlsl", defines_a, D3D_COMPILE_STANDARD_FILE_INCLUDE, "VS", "vs_5_0", flags, 0, &g_pVertexShaderBuffer, &pErrorBlob);
    if (FAILED(hr))
    {
        SAFE_RELEASE(pErrorBlob);
        ErrorBoxW(L"Cannot compile vertex shader VS vs_5_0.");
        return false;
    }

    hr = D3DCompileFromFile(L"PixelShader.hlsl", defines_a, D3D_COMPILE_STANDARD_FILE_INCLUDE, "PS", "ps_5_0", flags, 0, &g_pPixelShaderBuffer, &pErrorBlob);
    if (FAILED(hr))
    {
        SAFE_RELEASE(pErrorBlob);
        ErrorBoxW(L"Cannot compile pixel shader PS ps_5_0.");
        return false;
    }

    // Create the Shader Objects
    hr = g_pDevice->CreateVertexShader(g_pVertexShaderBuffer->GetBufferPointer(), g_pVertexShaderBuffer->GetBufferSize(), NULL, &g_pVertexShader);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create vertex shader.");
        return false;
    }

    hr = g_pDevice->CreatePixelShader(g_pPixelShaderBuffer->GetBufferPointer(), g_pPixelShaderBuffer->GetBufferSize(), NULL, &g_pPixelShader);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create pixel shader.");
        return false;
    }

    // Set Vertex and Pixel Shaders
    g_pDeviceContext->VSSetShader(g_pVertexShader, 0, 0);
    g_pDeviceContext->PSSetShader(g_pPixelShader, 0, 0);

    // Create the vertex buffer (vertices must be in clock-wise order)
    SimpleVertex vertices_a[] =
    {
        // Front Face
        /* 11 */ SimpleVertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 12 */ SimpleVertex(-1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 13 */ SimpleVertex(1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 14 */ SimpleVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),

        // Back Face
        /* 15 */ SimpleVertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),
        /* 16 */ SimpleVertex(1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 17 */ SimpleVertex(1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 18 */ SimpleVertex(-1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),

        // Top Face
        /* 19 */ SimpleVertex(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 20 */ SimpleVertex(-1.0f, 1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 21 */ SimpleVertex(1.0f, 1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 22 */ SimpleVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),

        // Bottom Face
        /* 23 */ SimpleVertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),
        /* 24 */ SimpleVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 25 */ SimpleVertex(1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 26 */ SimpleVertex(-1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),

        // Left Face
        /* 27 */ SimpleVertex(-1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 28 */ SimpleVertex(-1.0f,  1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 29 */ SimpleVertex(-1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 30 */ SimpleVertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),

        // Right Face
        /* 31 */ SimpleVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 32 */ SimpleVertex(1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 33 */ SimpleVertex(1.0f,  1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 34 */ SimpleVertex(1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),
    };

    D3D11_BUFFER_DESC vertexBufferDesc;
    ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));

    vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth = sizeof(SimpleVertex) * 24;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = 0;
    vertexBufferDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA vertexBufferData;
    ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
    vertexBufferData.pSysMem = vertices_a;
    hr = g_pDevice->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &g_pTriangleVertexBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create triangle buffer.");
        return false;
    }

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

    DWORD indices_a[] =
    {
        // Front Face
        /*  5 */ 0,  1,  2,
        /*  6 */ 0,  2,  3,

        // Back Face
        /*  7 */ 4,  5,  6,
        /*  8 */ 4,  6,  7,

        // Top Face
        /*  9 */ 8,  9, 10,
        /* 10 */ 8, 10, 11,

        // Bottom Face
        /* 11 */ 12, 13, 14,
        /* 12 */ 12, 14, 15,

        // Left Face
        /* 13 */ 16, 17, 18,
        /* 14 */ 16, 18, 19,

        // Right Face
        /* 15 */ 20, 21, 22,
        /* 16 */ 20, 22, 23,
    };

    D3D11_BUFFER_DESC indexBufferDesc;
    ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));

    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA iinitData;
    ZeroMemory(&iinitData, sizeof(D3D11_SUBRESOURCE_DATA));
    iinitData.pSysMem = indices_a;
    hr = g_pDevice->CreateBuffer(&indexBufferDesc, &iinitData, &g_pSquareIndexBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create index buffer.");
        return false;
    }

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

    // Create the Input Layout
    hr = g_pDevice->CreateInputLayout(g_layout_a, g_numElements, g_pVertexShaderBuffer->GetBufferPointer(), g_pVertexShaderBuffer->GetBufferSize(), &g_pVertexLayout);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create input layout.");
        return false;
    }

    // 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
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = g_width; // divide by 4 to only use 1/4 of client area (width)
    viewport.Height = g_height; // divide by 4 to only use 1/4 of client area (height)
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;

    //Set the Viewport
    g_pDeviceContext->RSSetViewports(1, &viewport);

    // Create the buffer to send to the cbuffer in effect file
    D3D11_BUFFER_DESC constantBufferDesc;
    ZeroMemory(&constantBufferDesc, sizeof(D3D11_BUFFER_DESC));

    constantBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    constantBufferDesc.ByteWidth = sizeof(ConstantBufferPerObject);
    constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    constantBufferDesc.CPUAccessFlags = 0;
    constantBufferDesc.MiscFlags = 0;

    hr = g_pDevice->CreateBuffer(&constantBufferDesc, NULL, &g_pConstantBufferPerObject);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create constant buffer.");
        return false;
    }

    D3D11_RASTERIZER_DESC rasterizerDesc;
    ZeroMemory(&rasterizerDesc, sizeof(D3D11_RASTERIZER_DESC));

    rasterizerDesc.FillMode = D3D11_FILL_SOLID;
    rasterizerDesc.CullMode = D3D11_CULL_NONE;
    rasterizerDesc.FrontCounterClockwise = true;
    hr = g_pDevice->CreateRasterizerState(&rasterizerDesc, &g_pNoCullSolid);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create rasterizer state (no culling, solid).");
        return false;
    }

    rasterizerDesc.FillMode = D3D11_FILL_WIREFRAME;
    hr = g_pDevice->CreateRasterizerState(&rasterizerDesc, &g_pNoCullWireframe);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create rasterizer state (no culling, wireframe).");
        return false;
    }

    g_pDeviceContext->RSSetState(g_pNoCullSolid);

    hr = CreateWICTextureFromFile(g_pDevice, L"tcage.png", NULL, &g_pCageTexture);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create shader resource view (cage).");
        return false;
    }

    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory(&sampDesc, sizeof(sampDesc));

    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;

    hr = g_pDevice->CreateSamplerState(&sampDesc, &g_pCubeTextureSamplerState);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create sampler state.");
        return false;
    }

    D3D11_BLEND_DESC blendDesc; // Define the Blending Equation
    ZeroMemory(&blendDesc, sizeof(blendDesc));

    D3D11_RENDER_TARGET_BLEND_DESC rtbd;
    ZeroMemory(&rtbd, sizeof(rtbd));

    rtbd.BlendEnable = true;
    rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR;
    rtbd.DestBlend = D3D11_BLEND_BLEND_FACTOR;
    rtbd.BlendOp = D3D11_BLEND_OP_ADD;
    rtbd.SrcBlendAlpha = D3D11_BLEND_ONE;
    rtbd.DestBlendAlpha = D3D11_BLEND_ZERO;
    rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    rtbd.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    blendDesc.AlphaToCoverageEnable = false;
    blendDesc.RenderTarget[0] = rtbd;

    hr = g_pDevice->CreateBlendState(&blendDesc, &g_pTransparency);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create blend state.");
        return false;
    }

    // Create the Counter Clockwise and Clockwise Culling States
    D3D11_RASTERIZER_DESC cmdesc;
    ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC));

    cmdesc.FillMode = D3D11_FILL_SOLID;
    cmdesc.CullMode = D3D11_CULL_BACK;
    cmdesc.FrontCounterClockwise = true;
    hr = g_pDevice->CreateRasterizerState(&cmdesc, &g_pCCWCullSolid);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create ccw cull mode.");
        return false;
    }

    cmdesc.FrontCounterClockwise = false;
    hr = g_pDevice->CreateRasterizerState(&cmdesc, &g_pCWCullSolid);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create cw cull mode.");
        return false;
    }

    g_pSpriteBatch = new SpriteBatch(g_pDeviceContext);
    if (!g_pSpriteBatch)
    {
        ErrorBoxW(L"Cannot create sprite batch.");
        return false;
    }

    g_pSpriteFont = new SpriteFont(g_pDevice, L"arial.font");
    if (!g_pSpriteFont)
    {
        ErrorBoxW(L"Cannot create sprite font.");
        return false;
    }

    XMStoreFloat3(&g_camera._target, CAMERA_TARGET_START);
    XMStoreFloat3(&g_camera._pos, CAMERA_POS_START);
    XMStoreFloat3(&g_camera._up, CAMERA_UP_START);
    g_camera._viewRotXZ = CAMERA_TARGET_VIEW_XZ_START;
    g_camera._viewRotY = CAMERA_TARGET_VIEW_Y_START;

    // Set the Projection matrix
    XMStoreFloat4x4(&g_camera._cameraProjection, XMMatrixPerspectiveFovLH(XMConvertToRadians(45.0f), (float)g_width / (float)g_height, 0.1f, 1000.0f));

    return true;
}

bool InitD3D11(void)
{   
    HRESULT hr;

    DXGI_MODE_DESC bufferDesc; // Describe our Buffer
    ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

    bufferDesc.Width = g_width;
    bufferDesc.Height = g_height;
    bufferDesc.RefreshRate.Numerator = 60;
    bufferDesc.RefreshRate.Denominator = 1;
    bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc; // Describe our SwapChain
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

    swapChainDesc.BufferDesc = bufferDesc;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 1;
    swapChainDesc.OutputWindow = g_hwnd;
    swapChainDesc.Windowed = TRUE;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    //Create our SwapChain
    hr = D3D11CreateDeviceAndSwapChain(
        NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        D3D11_CREATE_DEVICE_DEBUG,
        NULL,
        NULL,
        D3D11_SDK_VERSION,
        &swapChainDesc,
        &g_pSwapChain,
        &g_pDevice,
        NULL,
        &g_pDeviceContext);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create swap chain, device and device context.");
        return false;
    }

    ID3D11Texture2D* backBuffer; // Create our BackBuffer
    hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&backBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create back buffer.");
        return false;
    }

    // Create our Render Target
    hr = g_pDevice->CreateRenderTargetView(backBuffer, NULL, &g_pRenderTargetView);
    SAFE_RELEASE(backBuffer); // release back buffer in any case
    if (FAILED(hr))
    {   
        ErrorBoxW(L"Cannot create render target view.");
        return false;
    }

    D3D11_TEXTURE2D_DESC depthStencilDesc; // Describe our Depth/Stencil Buffer
    ZeroMemory(&depthStencilDesc, sizeof(D3D11_TEXTURE2D_DESC));

    depthStencilDesc.Width = g_width;
    depthStencilDesc.Height = g_height;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.ArraySize = 1;
    depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilDesc.SampleDesc.Count = 1;
    depthStencilDesc.SampleDesc.Quality = 0;
    depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthStencilDesc.CPUAccessFlags = 0;
    depthStencilDesc.MiscFlags = 0;

    // Create the Depth/Stencil View
    hr = g_pDevice->CreateTexture2D(&depthStencilDesc, NULL, &g_pDepthStencilBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create depth stencil buffer.");
        return false;
    }

    hr = g_pDevice->CreateDepthStencilView(g_pDepthStencilBuffer, NULL, &g_pDepthStencilView);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create depth stencil view.");
        return false;
    }

    // Set our Render Target
    g_pDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);

    return true;
}

void CleanUp(void)
{
    SAFE_RELEASE(g_pDevice);
    SAFE_RELEASE(g_pDeviceContext);
    SAFE_RELEASE(g_pPixelShader);
    SAFE_RELEASE(g_pPixelShaderBuffer);
    SAFE_RELEASE(g_pRenderTargetView);
    SAFE_RELEASE(g_pSwapChain);
    SAFE_RELEASE(g_pTriangleVertexBuffer);
    SAFE_RELEASE(g_pVertexLayout);
    SAFE_RELEASE(g_pVertexShader);
    SAFE_RELEASE(g_pVertexShaderBuffer);
    SAFE_RELEASE(g_pSquareIndexBuffer);
    SAFE_RELEASE(g_pDepthStencilBuffer);
    SAFE_RELEASE(g_pDepthStencilView);
    SAFE_RELEASE(g_pConstantBufferPerObject);
    SAFE_RELEASE(g_pNoCullSolid);
    SAFE_RELEASE(g_pNoCullWireframe);
    SAFE_RELEASE(g_pCageTexture);
    SAFE_RELEASE(g_pBrickTexture);
    SAFE_RELEASE(g_pCubeTextureSamplerState);
    SAFE_RELEASE(g_pTransparency);
    SAFE_RELEASE(g_pCWCullSolid);
    SAFE_RELEASE(g_pCCWCullSolid);
    SAFE_DELETE(g_pSpriteBatch);
    SAFE_DELETE(g_pSpriteFont);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // Check message
    switch (msg)
    {
    case WM_KEYDOWN:
        // if escape key was pressed, display popup box         
        if (wParam == VK_ESCAPE)
        {
            if (MessageBox(0, L"Are you sure you want to exit?", L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES)
            {
                // Release the windows allocated memory  
                DestroyWindow(hwnd);
            }
        }
        return 0;

    case WM_DESTROY:
        // if x button in top right was pressed
        PostQuitMessage(0);
        return 0;
    }

    // return the message for windows to handle it
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(hPrevInstance);

    g_hinstance = hInstance;

    WNDCLASSEX wc; // Create a new extended windows class
    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX); // Size of our windows class
    wc.style = CS_HREDRAW | CS_VREDRAW; // class styles
    wc.lpfnWndProc = WndProc; // Default windows procedure function
    wc.cbClsExtra = NULL; // Extra bytes after our wc structure
    wc.cbWndExtra = NULL; // Extra bytes after our windows instance
    wc.hInstance = hInstance; // Instance to current application
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Title bar Icon
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Default mouse Icon
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); // Window bg color
    wc.lpszMenuName = NULL; // Name of the menu attached to our window
    wc.lpszClassName = g_windowClassName; // Name of our windows class
    wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // Icon in your taskbar

    if (!RegisterClassEx(&wc)) // Register our windows class
    {
        ErrorBoxW(L"Error registering class");
        return 1;
    }

    // Create our Extended Window
    g_hwnd = CreateWindowEx(
        NULL, // Extended style
        g_windowClassName, // Name of our windows class
        g_windowTitle, // Name in the title bar of our window
        WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX), // style of our window
        CW_USEDEFAULT, CW_USEDEFAULT, // Top left corner of window
        g_width, // Width of our window
        g_height, // Height of our window
        NULL, // Handle to parent window
        NULL, // Handle to a Menu
        hInstance, // Specifies instance of current program
        NULL // used for an MDI client window
        );

    // Make sure our window has been created
    if (!g_hwnd)
    {
        ErrorBoxW(L"Error creating window");
        return 1;
    }

    ShowWindow(g_hwnd, nShowCmd); // Shows our window
    UpdateWindow(g_hwnd); // Its good to update our window

    bool result;
    result = InitD3D11();
    if (result)
    {
        result = InitScene();
        if (result)
        {
            MSG msg; // Create a new message structure
            ZeroMemory(&msg, sizeof(MSG));

            DWORD timeLast = timeGetTime();
            DWORD timeCurr = timeLast;
            float timeDelta = 0.0f;
            bool run = true;
            //float elapsed = 0.0f;
            //float frameLimit = 1.0f / 60.0f;

            while (run)
            {
                // if there was a windows message
                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    // if the message was WM_QUIT
                    if (msg.message == WM_QUIT)
                    {
                        run = false; // Exit the message loop
                    }

                    TranslateMessage(&msg); // Translate the message
                    DispatchMessage(&msg); // Send the message to default windows procedure
                }

                timeCurr = timeGetTime();
                timeDelta = (float)(timeCurr - timeLast) / 1000.0f;

                //elapsed += timeDelta;
                //if (elapsed >= frameLimit)
                //{
                g_fps.Calc(timeDelta);

                UpdateScene(timeDelta);
                DrawScene();

                //elapsed = 0.0f;
                //}

                timeLast = timeCurr;
            }
        }
    }

    CleanUp();

    return 0; // return the message
}

Сцена без SpriteFont

Сцена со SpriteFont

Другие вопросы по тегам