En aquesta secció, aprendrem a crear la nostra primera aplicació utilitzant DirectX. Aquest procés inclou la configuració inicial, la creació d'una finestra bàsica i la inicialització de Direct3D. Segueix els passos següents per començar.

  1. Configuració Inicial

Requisits Previs

Abans de començar, assegura't de tenir instal·lats els següents components:

  • Visual Studio (preferiblement la versió més recent)
  • DirectX SDK (si no està inclòs en el teu Visual Studio)

Crear un Nou Projecte

  1. Obre Visual Studio.
  2. Selecciona File > New > Project.
  3. Tria Windows Desktop Application i assegura't que el tipus de projecte sigui Empty Project.
  4. Assigna un nom al teu projecte i selecciona la ubicació on vols guardar-lo.

  1. Crear una Finestra Bàsica

Incloure les Llibreries Necessàries

Afegeix les següents llibreries al teu projecte per utilitzar les funcions de Windows i DirectX:

#include <windows.h>
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")

Definir la Funció WinMain

La funció WinMain és el punt d'entrada de les aplicacions Windows. Aquí és on inicialitzarem la finestra.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow) {
    // Definir i registrar la classe de finestra
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = "WindowClass";
    RegisterClassEx(&wc);

    // Crear la finestra
    HWND hwnd = CreateWindowEx(NULL, "WindowClass", "DirectX Application", WS_OVERLAPPEDWINDOW, 300, 300, 800, 600, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdshow);

    // Bucle de missatges
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

Definir la Funció WindowProc

La funció WindowProc gestiona els missatges de la finestra.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

  1. Inicialitzar Direct3D

Crear Dispositiu i Context de Dispositiu

Afegeix el següent codi per inicialitzar Direct3D:

IDXGISwapChain *swapchain;             // la cadena d'intercanvi
ID3D11Device *dev;                     // el dispositiu
ID3D11DeviceContext *devcon;           // el context del dispositiu

void InitD3D(HWND hwnd) {
    // Descripció de la cadena d'intercanvi
    DXGI_SWAP_CHAIN_DESC scd;
    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
    scd.BufferCount = 1;
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scd.OutputWindow = hwnd;
    scd.SampleDesc.Count = 4;
    scd.Windowed = TRUE;
    scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    // Crear el dispositiu, el context del dispositiu i la cadena d'intercanvi
    D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &scd, &swapchain, &dev, NULL, &devcon);
}

Configurar el Render Target

Afegeix el següent codi per configurar el render target:

ID3D11RenderTargetView *backbuffer;

void CreateRenderTarget() {
    // Obtenir el buffer de la cadena d'intercanvi
    ID3D11Texture2D *pBackBuffer;
    swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // Crear el render target view
    dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
    pBackBuffer->Release();

    // Configurar el render target
    devcon->OMSetRenderTargets(1, &backbuffer, NULL);
}

Configurar el Viewport

Afegeix el següent codi per configurar el viewport:

void SetViewport() {
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = 800;
    viewport.Height = 600;
    devcon->RSSetViewports(1, &viewport);
}

Integrar la Inicialització a WinMain

Actualitza la funció WinMain per incloure la inicialització de Direct3D:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow) {
    // Definir i registrar la classe de finestra
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = "WindowClass";
    RegisterClassEx(&wc);

    // Crear la finestra
    HWND hwnd = CreateWindowEx(NULL, "WindowClass", "DirectX Application", WS_OVERLAPPEDWINDOW, 300, 300, 800, 600, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdshow);

    // Inicialitzar Direct3D
    InitD3D(hwnd);
    CreateRenderTarget();
    SetViewport();

    // Bucle de missatges
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Alliberar recursos
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();

    return msg.wParam;
}

  1. Renderitzar un Color de Fons

Afegir la Funció de Renderització

Afegeix la següent funció per renderitzar un color de fons:

void RenderFrame() {
    // Especificar el color de fons
    float color[4] = {0.0f, 0.2f, 0.4f, 1.0f};
    devcon->ClearRenderTargetView(backbuffer, color);

    // Intercanviar els buffers
    swapchain->Present(0, 0);
}

Integrar la Funció de Renderització al Bucle de Missatges

Actualitza el bucle de missatges per cridar la funció RenderFrame:

MSG msg;
while (TRUE) {
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        if (msg.message == WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    } else {
        RenderFrame();
    }
}

Conclusió

En aquesta secció, hem creat la nostra primera aplicació DirectX. Hem configurat una finestra bàsica, inicialitzat Direct3D, configurat el render target i el viewport, i hem renderitzat un color de fons. Aquest és el primer pas per començar a treballar amb DirectX. En les següents seccions, aprofundirem en conceptes més avançats i començarem a renderitzar objectes 3D.

Exercici Pràctic:

  • Modifica el color de fons a un altre color de la teva elecció.
  • Afegeix un comptador de fotogrames per segon (FPS) a la finestra.

Solució de l'Exercici:

// Modificar el color de fons
float color[4] = {0.0f, 0.5f, 0.0f, 1.0f}; // Color verd

// Comptador de FPS
#include <chrono>
auto start = std::chrono::high_resolution_clock::now();
int frameCount = 0;

while (TRUE) {
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        if (msg.message == WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    } else {
        RenderFrame();
        frameCount++;
        auto end = std::chrono::high_resolution_clock::now();
        std::chrono::duration<float> duration = end - start;
        if (duration.count() >= 1.0f) {
            char title[256];
            sprintf_s(title, "DirectX Application - FPS: %d", frameCount);
            SetWindowText(hwnd, title);
            frameCount = 0;
            start = std::chrono::high_resolution_clock::now();
        }
    }
}

Amb aquests canvis, hauràs personalitzat el color de fons i afegit un comptador de FPS a la teva aplicació.

© Copyright 2024. Tots els drets reservats