Direct3D 9 Tutorial

In deze tutorial ga ik je uitleggen hoe je Direct3D werkt. Direct3D is een onderdeel van DirectX waarmee je de graphics in je spel/programma regelt. Voor degene die niet weten wat DirectX is: DirectX is een verzameling DLL's (gemaakt door Microsoft) die handige en snelle functies bevatten voor game/multimedia programmeurs. Voor meer informatie over DirectX verwijs ik je naar www.microsoft.com/directx/

De versie van DirectX die ik in deze tutorial ga gebruiken in DirectX 9.0. Als je een andere versie hebt, bv. 8.0 of 8.1 is het ook goed, maar er zitten kleine verschillen tussen de API's. Voordat je begint moet je eerst de DirectX SDK downloaden. Als je hem nog niet hebt, klik dan hier om hem te downloaden.

In deze tutorial zal ik Visual C++ gebruiken. Je kan natuurlijk ook een andere compiler gebruiken, maar dan zal de code niet gegarandeerd werken. Je kan natuurlijk altijd vragen stellen in het forum als het niet lukt.

Nadat je de SDK hebt gedownload, installeer je hem (naar bv. Visual C++ Map\DXSDK\). Als het goed is worden de include en library directories automatisch bijgewerkt in VC++. Anders moet je dat handmatig instellen.

Handmatig instellen (bij VC++.NET, dit kan verschillen bij andere versies):
1. Ga naar "Tools" en het menu en klik op "Options".
2. In de dialoog die nu tevoorschijn komt zie je links een soort mappenlijst. Klik op de map "Projects".
3. Klik op de sub-map "VC++ Directories".
4. Kies bij "Show directories for: ", "Include files"
5. Klik op de knop met een pictogram van een map om een nieuw adres toe te voegen waar VC++ moet zoeken voor header files
6. Typ hier Je_SDK_Directory\Include (niet letterlijk natuurlijk)
7. Kies dan bij "Show directories for: ", "Library files".
8. Klik weer op het knopje met een pictogram van een map
9. Typ hier Je_SDK_Directory\Lib

Als het goed is moet het nu werken.

Maak nu een nieuw Win32 project aan en voeg d3d9.lib toe aan je libraries. Hierdoor kun je Direct3D functies gebruiken.


Direct3D initialiseren

Voordat je wat op het scherm kan zetten, moet je eerst Direct3D initialiseren.

#include <d3d9.h> // Direct3D header bestand

LPDIRECT3D9 g_pD3D = NULL; // Pointer naar Direct3D interface
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL; // Pointer naar Direct3D device


De g_pD3D variabel wijst naar de Direct3D interface (IDirect3D9) . LPDIRECT3D9 is getypedeft als een pointer naar IDirect3D9 en LPDIRECT3DDEVICE9 naar IDirect3DDevice9 (logisch natuurlijk).
Met de Direct3D interface kun je Direct3D initialiseren en vervolgens een Direct3D device (IDirect3DDevice9) creŽren. Bekijk de code hieronder.

BOOL InitDirect3D(HWND hWnd)
{
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION); // CreŽr Direct3D interface

if(g_pD3D == NULL)
{
return FALSE;
}

...


Met de functie Direct3DCreate9() creŽr je de Direct3D interface.

...

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory(&d3dpp, sizeof(d3dpp); // Maak de structure leeg
d3dpp.Windowed = TRUE; // We willen een window, geen volledig scherm
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Swapeffect
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // Formaat van de backbuffer

// CreŽr Direct3D device
if(FAILED(g_pD3D->CreateDevice(D3D_ADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice);
{
return FALSE;
}

return TRUE; // Direct3D is klaar voor gebruik
}

De D3DPRESENT_PARAMETERS structure geeft aan hoe of wat de backbuffer naar de frontbuffer wordt gekopieerd. De backbuffer is zeg maar een onzichtbaar scherm. Elk frame dat getekend wordt, wordt eerst opgeslagen in de backbuffer, als het frame af is, wordt het naar de frontbuffer gekopieerd (ook wel "flippen" genoemd).
Deze structure heb je nodig in de CreateDevice() functie. Ik zal de parameters van deze functie even uitleggen. De eerste parameter is de video adapter (= videokaart). Gebruik hier D3D_ADAPTER_DEFAULT voor standaard adapter. De tweede parameter is het device type dat je wilt hebben. Gebruik hier D3DDEVTYPE_HAL om de hardware te gebruiken. De volgende parameter is gewoon de handle naar je window. In de vierde parameter geef je met D3DCREATE_SOFTWARE_VERTEXPROCESSING aan dat je de hardware wil gebruiken voor vertexprocessing (je hoeft niet te weten wat dit is). De laatste twee parameters is een pointer naar de D3DPRESENT_PARAMETERS structure en een pointer naar de D3DDevice.

Nu heb je een Direct3D device. We gaan verder met de Render() functie. In deze tutorial gaan we nog niks op het scherm tekenen, maar we maken deze functie alvast voor latere tutorials.


Render


Deze functie wordt geroepen om een frame te renderen. Als je spel geen window messages ontvangt oid. kun je een deze functie roepen.

void Render()
{
// Maak het scherm leeg
g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0.0f);

...


Voordat je iets op het scherm gaat tekenen, moet je eerst het scherm leeg maken (ik noem het voor het gemak even clearen). Anders wordt het een troepzootje op je scherm. Dit doe je met de Clear() functie van IDirect3DDevice. In de clearen. Dat willen we niet, dus we zetten ze op 0 (en de tweede op NULL, want dat is een pointer), we willen dat het hele scherm gecleared wordt. De eerste parameter is trouwens de grootte van de array met rechthoeken dat gecleared moet worden en de tweede parameter het adres daar naartoe.
De derde parameter geeft aan hoe het scherm gecleared moet worden. Zet hier D3DCLEAR_TARGET neer om het scherm te clearen naar een kleur die je aangeeft in de volgende parameter. Er zit een handige macro in DirectX om van RGB waardes een DWORD te maken, namelijk D3DCOLOR_XRGB(rood, groen, blauw). In deze code wordt het scherm dus groen. De laatste twee parameters zijn de niet zo belangrijk. Zie MSDN voor verdere informatie.

We zijn nu bij het belangrijkste deel van je spel: het gedeelte waarmee je iets op het scherm zet.

...

g_pD3DDevice->BeginScene(); // Begin scene

// Tussen BeginScene en EndScene kun je teken functies gebruiken

g_pD3DDevice->EndScene(); // End scene

// LET OP: Vergeet dit niet, met deze functie wordt de inhoud van de
// backbuffer naar de frontbuffer gekopieerd, zodat je iets ziet
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);

}


Voor deze code is geen verdere uitleg nodig. De parameters bij de Present functie zijn opties die je later nog kunt gebruiken, maar die heb je nu nog niet nodig, dus zet ze op NULL.


Clean up, Ruim alles weer netjes op

Aan het einde van het spel moet je Direct3D uitschakelen. Dit doe je door de objecten te releasen (loslaten). Je moet dit in dit geval bij twee objecten doen: Direct3D en Direct3D device.


void CleanUp()
{
if(g_pD3D != NULL) // Controleer of Direct3D wel geinitialiseerd is
g_pD3D->Release(); // Zoja, release hem

if(g_pD3DDevice != NULL) // Controleer of er wel een Direct3D device is
g_pD3DDevice->Release(); // Zoja, release hem
}


Je controleert eerst of het object wel geinitialiseerd is, dus of de pointer niet naar niks wijst (NULL) en daarna release je het object door object->Release() aan te roepen.

Nu moet je nog een WinMain functie maken die een window maakt en daarna onze InitDirect3D functie aanroept. Je hebt ook nog een gameloop functie en een WndProc nodig. In de gameloop controleer je of er windows messages zijn, zoniet, render een frame. Als je niet meer precies weet hoe dit moet, bekijk dan de vorige tutorials dan nog eens.

Golddust