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.
- 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
- Obre Visual Studio.
- Selecciona File > New > Project.
- Tria Windows Desktop Application i assegura't que el tipus de projecte sigui Empty Project.
- Assigna un nom al teu projecte i selecciona la ubicació on vols guardar-lo.
- 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:
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); }
- 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; }
- 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ó.
Curs de Programació DirectX
Mòdul 1: Introducció a DirectX
- Què és DirectX?
- Configuració de l'Entorn de Desenvolupament
- Comprendre l'API de DirectX
- Crear la Teva Primera Aplicació DirectX
Mòdul 2: Conceptes Bàsics de Direct3D
- Introducció a Direct3D
- Inicialitzar Direct3D
- Renderitzar un Triangle
- Gestionar el Bucle de Renderització
Mòdul 3: Treballar amb Shaders
Mòdul 4: Tècniques Avançades de Renderització
Mòdul 5: Models 3D i Animació
Mòdul 6: Optimització del Rendiment
- Perfilat i Depuració
- Optimitzar el Rendiment de la Renderització
- Gestió de Memòria
- Multifil en DirectX