En aquest tema, aprendrem a inicialitzar Direct3D, que és una part fonamental per començar a treballar amb gràfics 3D en DirectX. La inicialització de Direct3D implica configurar diversos components essencials com el dispositiu Direct3D, el context del dispositiu i la cadena d'intercanvi (swap chain).
Objectius
- Comprendre els components bàsics necessaris per inicialitzar Direct3D.
- Escriure codi per crear i configurar el dispositiu Direct3D i la cadena d'intercanvi.
- Gestionar errors comuns durant la inicialització.
Components Bàsics
- Dispositiu Direct3D (Direct3D Device)
El dispositiu Direct3D és l'objecte principal que utilitzem per renderitzar gràfics. Proporciona mètodes per crear recursos gràfics, configurar l'estat de renderització i enviar comandes de dibuix a la GPU.
- Context del Dispositiu (Device Context)
El context del dispositiu és utilitzat per configurar l'estat de renderització i emetre comandes de dibuix. Hi ha dos tipus de contextos: immediat i diferit. En aquest tema, ens centrarem en el context immediat.
- Cadena d'Intercanvi (Swap Chain)
La cadena d'intercanvi és responsable de gestionar les superfícies de renderització i presentar-les a la pantalla. Conté una sèrie de buffers que s'utilitzen per emmagatzemar les imatges renderitzades abans de mostrar-les.
Passos per Inicialitzar Direct3D
- Incloure les Llibreries Necessàries
Primer, hem d'incloure les llibreries Direct3D i les capçaleres necessàries en el nostre projecte.
#include <d3d11.h> #include <dxgi.h> #include <d3dcompiler.h> #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "d3dcompiler.lib")
- Definir Variables Globals
Definim les variables globals per al dispositiu Direct3D, el context del dispositiu i la cadena d'intercanvi.
ID3D11Device* g_pd3dDevice = nullptr; ID3D11DeviceContext* g_pImmediateContext = nullptr; IDXGISwapChain* g_pSwapChain = nullptr; ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
- Crear el Dispositiu i la Cadena d'Intercanvi
Utilitzem la funció D3D11CreateDeviceAndSwapChain per crear el dispositiu Direct3D i la cadena d'intercanvi.
HRESULT InitD3D(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = 800;
sd.BufferDesc.Height = 600;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
HRESULT hr = D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&sd,
&g_pSwapChain,
&g_pd3dDevice,
nullptr,
&g_pImmediateContext
);
if (FAILED(hr))
{
return hr;
}
// Crear la vista de renderització
ID3D11Texture2D* pBackBuffer = nullptr;
hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if (FAILED(hr))
{
return hr;
}
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
pBackBuffer->Release();
if (FAILED(hr))
{
return hr;
}
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);
// Configurar la vista de la finestra
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)800;
vp.Height = (FLOAT)600;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports(1, &vp);
return S_OK;
}
- Alliberar Recursos
És important alliberar els recursos quan ja no els necessitem per evitar fuites de memòria.
void CleanupDevice()
{
if (g_pImmediateContext) g_pImmediateContext->ClearState();
if (g_pRenderTargetView) g_pRenderTargetView->Release();
if (g_pSwapChain) g_pSwapChain->Release();
if (g_pImmediateContext) g_pImmediateContext->Release();
if (g_pd3dDevice) g_pd3dDevice->Release();
}Exercici Pràctic
Exercici 1: Inicialitzar Direct3D
- Crea un projecte nou en Visual Studio.
- Inclou les llibreries i capçaleres necessàries.
- Defineix les variables globals per al dispositiu Direct3D, el context del dispositiu i la cadena d'intercanvi.
- Implementa la funció
InitD3Dper inicialitzar Direct3D. - Implementa la funció
CleanupDeviceper alliberar els recursos. - Executa el projecte i assegura't que la finestra es crea correctament sense errors.
Solució de l'Exercici
#include <d3d11.h>
#include <dxgi.h>
#include <d3dcompiler.h>
#include <windows.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
ID3D11Device* g_pd3dDevice = nullptr;
ID3D11DeviceContext* g_pImmediateContext = nullptr;
IDXGISwapChain* g_pSwapChain = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
HRESULT InitD3D(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = 800;
sd.BufferDesc.Height = 600;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
HRESULT hr = D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&sd,
&g_pSwapChain,
&g_pd3dDevice,
nullptr,
&g_pImmediateContext
);
if (FAILED(hr))
{
return hr;
}
ID3D11Texture2D* pBackBuffer = nullptr;
hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if (FAILED(hr))
{
return hr;
}
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
pBackBuffer->Release();
if (FAILED(hr))
{
return hr;
}
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)800;
vp.Height = (FLOAT)600;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports(1, &vp);
return S_OK;
}
void CleanupDevice()
{
if (g_pImmediateContext) g_pImmediateContext->ClearState();
if (g_pRenderTargetView) g_pRenderTargetView->Release();
if (g_pSwapChain) g_pSwapChain->Release();
if (g_pImmediateContext) g_pImmediateContext->Release();
if (g_pd3dDevice) g_pd3dDevice->Release();
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"Direct3DWindowClass";
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
return 0;
HWND hWnd = CreateWindow(
L"Direct3DWindowClass",
L"Direct3D Initialization",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
800, 600,
nullptr, nullptr,
hInstance,
nullptr
);
if (!hWnd)
return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (FAILED(InitD3D(hWnd)))
{
CleanupDevice();
return 0;
}
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CleanupDevice();
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}Conclusió
En aquest tema, hem après a inicialitzar Direct3D configurant el dispositiu Direct3D, el context del dispositiu i la cadena d'intercanvi. També hem vist com alliberar els recursos per evitar fuites de memòria. Aquest és un pas fonamental per començar a treballar amb gràfics 3D en DirectX. En el següent tema, aprendrem a renderitzar un triangle utilitzant Direct3D.
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
