Documente Academic
Documente Profesional
Documente Cultură
SuportDirect3D ROM Lectia2
SuportDirect3D ROM Lectia2
Pereteatcu
2. DirectX 9
Destinaţia DirectX 9
DirectX — este bibliotecă multimedia, care permite lucrul direct cu dispozitivele periferice ale
computerului fără de a utiliza mijloacele tradiţionale ale platformei Win32. interacţiunea directă
a lui DirectX cu dispozitive dotate cu driverele elaborate de către producătorii ale acestor
dispozitive. Ca rezultat, tehnologia aceasta permite abstractizare completă de partea dispozitivă
şi concentrarea eforturilor la crearea nemijlocită a codului. Toată biblioteca DirectX 9 se
divizează în componente care răspund pentru partea respectivă a lucrului bibliotecii:
DirectX Graphics;
DirectInput;
DirectMusic;
DirectSound;
DirectPlay;
DirectShow;
DirectSetup.
În fig. 2.1 este prezentată schema generală de interacţiune a DirectX 9 cu unităţile periferice ale
computerului.
DirectX Graphics
DirectInput
DirectMusic
Application DirectSound HAL Hardware
DiredPlay
DirectShow
DirectSetup
18
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
Componente DirectX 9
Vom face cunoştinţă cu patru componente din DirectX 9. Acestea sunt Direct3D (întră în
componenţa DirectX Graphics), DirectInput, DirectMusic şi DirectSound. Toate patru se
folosesc la programarea jocurilor computerizate. Ceea ce se referă la sunet, în principiu va fi
îndeajuns numai DirectMusic, totuşi cu scopul de cunoştinţelor mai generale vor fi descrise şi
careva din componente ale DirectSound.
În versiunile precedente (inclusiv până la 7) DirectX Graphics a fost divizat în două părţi:
DirectDraw şi Direct3D. DirectDraw răspundea de grafica 2D, pe când Direct3D răspundea de
grafica 3D. În versiunea a 8 DirectX DirectDraw a fost inclusă în Direct3D. A devenit epoca
jocurilor 3D, ar grafica 2D deja nu este de mirare. Cu apariţia DirectX 9 practic nimic nu s-a
schimbat. Totuşi accesul la DirectDraw a rămas, însă cât el este de actual? În orice caz ne vom
ocupa numai cu Direct3D, care răspunde de lucru cu grafica 3D.
DirectMusic, — după cum se vede din denumire, răspunde de lucru cu muzică. În mare parte
asigură lucru cu MIDI (Musical Instrument Digital Interface). Există posibilitatea de a interpreta
şi fişierele WAV. Componenta DirectMusic este forte complicată. Ea nu este limitată numai cu
interpretarea fişierelor MIDI sau WAV.
DirectSound — este partea din DirectX 9 care răspunde de sunet şi permite de a utiliza buferr-ele
de bază (principale), suplimentare (ajutătoare), de statistică şi de flux, care asigură diferite efecte
de sunet.
DirectPlay asigură interacţiunea aplicaţiei noastre cu reţea locală sau cu reţea Internet pentru
modul multiuser de jocuri. Componenta DirectPlay este construită pe baza protocolului propriu,
care asigură lucrul cu toate protocoale de reţea.
DirectShow este necesară pentru lucru cu video torenţial, în particular, serveşte pentru capturarea
şi reprezentarea video de diferite formate: MPEG (Motion Picture Experts Group), MPEG Audio
Layer-3 (cunoscut pentru toţi ca formatul MP3) şi, fără îndoială Audio-Video Interleaved (AVI).
Deci, DirectX 9 — este o bibliotecă foarte mare, care răspunde de lucru cu componentele
multimedia ale calculatorului. Ea asigură productivitatea înaltă şi, cel mai important, permite
programatorului, care elaborează aplicaţia, să nu se gândească la partea hard a calculatorului.
19
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
HAL
DirectX include în sine nivelul de abstractizare — HAL (Hardware Abstraction Layer — nivelul
de abstractizare a echipamentului), care permite reglarea setărilor pentru orice echipament şi
dispozitive.
СОМ
Toată biblioteca DirectX este construită pe baza СОМ (Component Object Model) — modelul
de obiecte compuse. Neintrând detaliat în esenţa tehnologiei СОМ, reţinem că lucrul cu СОМ se
bazează pe apelurile funcţiilor respective. Totuşi principiile generale ale СОМ vor fi descrise.
În componenţa СОМ există biblioteca API, care se numeşte СОМ-bibliotecă. Cu ajutorul aceste
biblioteci se dirijează toate componentele. Fiecare din componentele-program realizează un
număr concret de obiecte-COM, accesul la care se realizează prin interfeţe, care, la rândul său,
sunt compuse din funcţii. Cu ajutorul acestor funcţii şi se face interacţiunea cu obiectul-COM.
Interfeţe în СОМ — reprezintă o structură strict definită, care conţine un vector de pointeri la
funcţii. Fiecare di componentele DirectX, de exemplu Direct3D, include un şir de interfeţe cu
setul respectiv de funcţii, cu ajutorul cărora se accesează obiectul-COM. Toate interfeţe în
DirectX au notaţia proprie care începe cu litera "I". Apoi urmează numele obiectului-COM, de
exemplu Direct3D, apoi numărul versiunii utilizate a bibliotecii DirectX, de exemplu:
IDirect3D9. Toate interfeţe sunt strict definite şi nu pot fi modificate, ceea ce permite accesul
la versiunile precedente ale interfeţelor.
Interfaţa IUnknown
Obiectul СОМ are un contor, care duce evidenţa a numărului de interfeţe utilizate. Cu fiecare
interfaţa nouă activată contorul se măreşte cu unu. Cu ajutorul funcţiei AddRef() se măreşte
contorul obiectului-СОМ indicat. Noi nu vom folosi funcţia aceasta, fiindcă mărirea contorului
de referinţe se face automat.
20
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
După ce interfaţa şi-a terminat lucru, ea se eliberează, iar contorul intern a obiectelor-СОМ se
micşorează cu unu. Imediat după ce valoarea contorului devine zero, obiectul-СОМ îşi descarcă
pe sine din memoria, şi tot în momentul acela, toate obiectele create de el, vor fi descărcate de
către sistem. Pentru decrementarea contorului răspunde funcţia Release(). De funcţia această
ne vom folosi permanent. Operaţia, efectuată de către funcţia Release(), se mai numeşte
"eliberarea resurselor ocupate". În viitor, în fiecare din proiecte pe care vom crea, vom introduce
câte o funcţie specială, care va elibera resursele ocupate prin apelurile funcţiei Release().
După cum deja a fost spus, DirectX 9 nu are interfaţa DirectDraw, care răspunde de grafica 2D.
Totuşi, dacă apare necesitatea de a obţine accesul la interfaţa aceasta, de exemplu, la versiunea a
şaptea DirectDraw7, o astfel posibilitate există, datorită faptului de compatibilitate strictă a
interfeţelor cu versiunile precedente. Pentru asta este prevăzută funcţia QueryInterface().
Din antetul funcţiei totul devine clar:
HRESULT QueryInterface(
REFIID iid,
void** ppvDest)
Aici nu mai ajung câteva operaţii, însă totul ser va clarifica pe parcursul studierii ulterioare a
materialului. În cazul în care funcţia QueryInterface() nu va eşua, interfaţa DirectDraw7
devine accesibilă.
Direct3D 9
Direct3D — este cea mai puternică şi cea mai principală componentă a DirectX 9. Ea răspunde
de desenare în grafică 3D, de suprapunerea texturilor pe obiecte, de vertex-shader şi pixeli-
shader, şi de multe altele. Cu ajutorul Direct3D Este posibil de a încorpora grafica 3D în aplicaţii
pentru platforma Windows. Având la dispoziţie un set mare de diferite funcţii, structuri,
macrouri, flaguri, programatorul este practic ferit de partea hard a computerului, fiind concentrat
asupra codului de program. Ultimul uşor se încorporează în aplicaţia şi interacţionează cu
aplicaţia.
Cea mai principală componentă a Direct3D este procesul de randare (rendering). Randarea —
este vizualizarea obiectului 3D pe ecran al monitorului. Este important de înţeles, că orice obiect
se păstrează în memoria video ori operativă a computerului ca un constructor descompus în părţi.
Fiecare parte răspunde de careva componentă a obiectului. De exemplu, robotul este construit
din cap, picioare, mâni, corp. Tot aşa şi obiectul este compus din părţi cum sunt texturi, lumină,
material, poligoane şi multe altele. Pentru a vedea în constructorul un robot întreg, ultimul
trebuie să asamblat din părţi, să treacă prin procesul de asamblare. Tot aşa, pentru a vedea pe
ecran al monitorului un obiect, ultimul trebuie să treacă prin procesul de randare, care şi va face
asamblarea obiectului. În conceptul general, prin obiect se subînţelege nu numai un singur model
3D luat aparte, dar şi mediul care o înconjoară. În Direct3D asta se numeşte scenă.
21
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
În întregime procesul de randare constă din câteva mecanisme. Principalele sunt: mozaicare
(tessellation), transformare, iluminare, rasterizare. Cu ajutorul acestor mecanisme se obţine
vizualizarea pe ecran al monitorului a scenei întregi.
Iluminare (lighting) — este o analogie directă cu mediul înconjurător, în care toate obiectele au
culoarea, care la rândul său depinde de surse de lumină.
Rasterizare (rasterizer) — este cel mai complicat mecanism din cele numite mai sus. El
desenează pe ecran al monitorului toată scena, reprezentând-o la nivelul de pixeli. Pentru asta se
face texturarea, Z-bufferizare, calcularea umbrelor, alfa-amestecarea (alfa-blending), eliminarea
suprafeţelor ascunse şi multe altele.
Crearea aplicaţiei tip fereastră. Aceasta este ceea ce a fost făcut în primul proiect, anume, a fost
creată fereastra în regimul selectat şi aspectul dorit. Prin asta s-a creat suprafaţa de lucru. Mai
departe vom integra în acest proiect codul de dezvoltare şi funcţiile DirectX.
Iniţializarea Direct3D. Aici vom crea pointeri spre interfeţe necesare, vom iniţializa Direct3D 9,
vom seta parametrii de prezentare şi vom crea dispozitivul Direct3D. Dispozitivul Direct3D —
este, aşa numite, partea hard şi partea soft ale computerului. Adică noi setăm rezoluţia ecranului,
frecvenţa de regenerare a cadrelor, aflăm informaţii despre placa video, stabilim cum
videoadapterul va prelucra informaţiile propuse, setăm formatul buffer-ului din spate, setăm
parametrii bufferului de adâncime, deci, totul ce se referă la reglarea părţilor hard şi soft ale
computerului.
Crearea obiectului. Fiecare obiect, oricât de mare sau mic ar fi el, se compune din poligoane. De
obicei acestea sunt triunghiuri. Orice triunghi constă din trei colţuri, sau vertexuri. În Direct3D
se operează cu noţiunea de vertex. Un vertex este definit prin trei coordonate în spaţiu, respectiv
după axele X, Y şi Z. Ştiind toate acestea, plus la asta având cunoştinţe despre trigonometrie, se
poate de construit practic orice obiect. Prin setarea formatului vertexurilor, în dependenţă de
utilizare a transformărilor matriciale pentru randarea obiectului sau utilizare a formatului
transformat al vertexurilor pentru reprezentare a obiectului 2D pe ecran, noi creăm prin asta
obiectul.
Iluminare, material şi textură. O scenă reală poate fi prezentată pe ecran, numai dacă vom utiliza
iluminarea şi materiale. Numai creând diferite surse de lumină, de exemplu, bec, soare, foc, şi
setând materiale pentru obiecte, materiale care vor defini reflectarea luminii, vom adăuga
realitatea la scena care se desenează. Şi dacă vom aplica textura, de exemplu, în formă de parchet
de podea, vom atinge identitatea absolută cu mediul înconjurător.
Randarea obiectului. Redesenează scena pe ecran, luând în consideraţie diferite valori pentru
toate componente ale conveierului de randare.
22
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
Etapele susnumite, pentru claritate, au fost divizate condiţional în părţile componente. Totuşi
principiul general a fost descris. Mai departe vom analiza interfeţele din care constă Direct3D 9
şi cum să creează pointeri spre interfeţe necesare. În sfârşit, vom instala DirectX 9 SDK la
calculator.
Interfeţe Direct3D 9
Direct3D 9 conţine cel mai mare număr de diferite interfeţe. Ele răspund de texturare, de buffer-
ul vertexurilor, de buffer-ul indicilor, de vertex- şi pixeli-shader, de interfaţa cu dispozitive
Direct3D 9, etc. Să descriem pe scurt numai acele din interfeţe, pe care vom folosi nemijlocit în
proiectele viitoare:
IDirect3D9;
IDirect3DDevice9;
IDirect3DVertexBuffer9;
IDirect3DIndexBuffer9;
IDirect3DTexture9;
IDirect3DVertexShader9.
IDirect3D9 — este cea mai principală interfaţa, de la ea moştenesc toate celelalte interfeţe.
Interfaţa aceasta trebuie să fie instanţiată în primul rând. Şi numai după asta vom avea acces la
celelalte interfeţe şi funcţii.
23
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
vertexurilor deja este potrivită. În cazul de necesitate, buffer-ul de indici poate fi creat cu funcţia
IDirect3DIndexBuffer9::CreateIndexBuffer().
IDirect3DTexture9 — după cum se vede din nume, interfaţa aceasta răspunde de texturi.
Interfaţa conţine multe funcţii cu ajutorul cărora avem posibilitatea să suprapunem texturi pe
obiect, una peste alta, etc.
Din lista destul de mare au fost descrise doar acele interfeţe pe care vom utiliza mai departe. În
componenţa Direct3D 9 întră aşa numită biblioteca de utilite Direct3DX 9. Utilizând biblioteca
de utilite, avem posibilitatea să încărcăm obiecte create în 3DS МАХ, sau să efectuăm cu obiecte
transformări matriciale. Biblioteca aceasta, la rândul său, conţine multe interfeţe, careva din care
vor fi cercetate ulterior.
Prima metodă:
IDirect3D9* pDirect3D;
IDirect3DDevice9* pDirect3DDevice;
A doua metodă:
LPDIRECT3D9 pDirect3D;
LPDIRECT3DDEVICE pDirect3DDevice;
Amândouă metode aduc la unul şi acelaşi rezultat. Pentru a fi clar, de ce acesta este posibil,
demonstrăm specificarea pentru interfaţa IDirect3D9, care este asemănătoare cu specificări
pentru celelalte interfeţe:
typedef struct IDirect3D9 *LPDIRECT3D9 *PDIRECT3D9
După ce a fost declarat pointerul la interfaţa, putem crea şi însăşi obiect. Fiindcă am declarat câte
un pointer la interfeţe, respectiv IDirect3D9 şi IDirect3DDevice9, creăm şi câte un obiect
de fiecare interfaţă:
// pointerul la obiectul-interfaţa IDirect3D9
pDirect3D = Direct3DCreate9(D3D_SDK_VERSI0N);
// pointerul la obiectul-interfaţa IDirect3DDevice9
pDirect3D -> CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSWG,
&Direct3DParametr, &pDirect3DDevice);
În detalii, acţiunile acestea vor fi cercetate în secţiunile ulterioare. Deocamdată vom înţelege
sensul general de toate acţiunile, pentru a uşura înţelegerea materialului de mai departe. De la
început, se declară un pointer la interfaţă, mai precis, variabila în care se va păstra adresa unui
24
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
În mapa DirectX 9 SDK este fişierul dx90bsdk.de dimensiune 218 М. Acesta este versiunea
produsului DirectX 9.0b, care conţine bibliotecile pentru trei limbaje de programare: C++, С#,
Visual Basic.
Click dublu pe numele fişierului dx90bsdk în mapa DirectX 9 SDK. Aceasta va aduce la
despachetarea întregului SDK la calculator.
După despachetarea pe ecran al monitorului apare fereastra Microsoft DirectX 9.0 SDK -
InstallShield Wizard, cu posibilitatea alegerii a componentelor necesare. Opţiunea
DirectX Samples and Source Code propune la alegere documentaţia, exemple, coduri-
surse pentru trei limbaje de programare. Pe noi ne interesează nemijlocit C++, celelalte limbaje
după necesitate.
Să apăsăm butonul Next, ca rezultat se va deschide caseta de dialog, în care se va propune tipul
de instalare. Să setăm opţiunea Debug în regiunea DirectX Runtime Support. Să apăsăm
butonul Install Now pentru a continua instalarea.
După instalarea descrisă, în Visual C++ .NET, în locul de creare a unui proiect nou, la wizard-ii
standard (AppWizard) se va adăuga încă un wizard — DirectX 9 Visual C++ Wizard. Cu
ajutorul acestuia putem să creăm aplicaţii minimale de utilizare a DirectX 9. Cu astfel de
"carcasă" putem lucra mai departe. Totuşi, mai bine să creăm o "carcasă" proprie, care va
satisface necesităţilor noastre. Carcasa proprie poate fi adăugată la lista wizard-elor. Pentru
exemplu să creăm cu ajutorul wizard-ului o aplicaţie. Vom analiza ce rezultat vom obţine după
compilare.
Pe pagina activă Overview vor fi enumerate componentele, care pot fi instalate (incluse) în
aplicaţia. Mai jos, pe fiecare din trei pagini accesibile: Project Settings, Direct3D
Options, DirectInput Options putem să activăm (conectăm) sau să dezactivăm
(deconectăm) un şir de componente, enumerate pe pagina Overview. Să lăsăm totul cum este şi
să apăsăm butonul Finish. Astfel se va crea un proiect, completamente alcătuit de către wizard-
ul DirectX.
25
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
În Visual C++ .NET, pe pagina Solution Explorer din partea stânga va apărea mai mul de
20 de fişiere cu diferite extensii. Să compilăm acest proiect şi să analizăm rezultatul obţinut. Pe
ecran va apărea fereastra a unei aplicaţii simple. Pe suprafaţa de lucru a aplicaţiei va fi desenat
un ceainic frumos de culoare roşie. Cu ajutorul tastelor <Up>, <Left>, <Right>, <Down>
ceainicul poate fi rotit şi privit în detalii din toate părţile.
26
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
3. Iniţializarea Direct3D
Noţiune de iniţializare
Cunoaştem deja cum se creează o aplicaţie simplă de tip fereastră, care apare pe ecran al
monitorului în poziţia indicată, care are dimensiunile indicate, fundalul la care este umplut cu
culoarea indicată. Putem să schimbăm dimensiunile, stilul, culoarea fundalului şi punctul de
apariţie. Pentru asta trebuie să schimbăm valorile ale câmpurilor respective în structura creată
windowsclass.
Vom crea o funcţie care va răspunde pentru iniţializarea Direct3D 9. Vom numi-o
InitialDirect3D(). Mai întâi de toate vom pregăti un proiect nou.
Creăm în Visual C++ .NET un proiect gol nou de tip Windows application, cu numele
InitDirect3D. Să adăugăm în acest proiect un fişier gol cu acelaşi nume
InitDirect3D.cpp şi să copiem în acest fişier codul sursă din proiectul precedent.
Fişierul acesta conţine un număr mare de clase pentru Direct3D 9. Mai trebuie să conectăm şi
biblioteca d3d9.lib. Sunt două metode de a conecta o bibliotecă la proect.
Să cercetăm prima metodă. În fereastra de lucru Visual C++ .NET, pe pagina Solution
Explorer, executăm un click drept pe proiectul InitDirect3D, apare un meniu de context.
Alegem opţiunea Properties, după ce se va deschide caseta de dialog InitDirect3D Property
Pages (fig. 3.1). Apoi selectăm Linker/Input şi în caseta Additional Dependencies
scriem d3d9.1ib. Apăsăm ОК. Astfel biblioteca va fi adăugată în proiectul nostru. Adăugarea
bibliotecii este arătată în fig. 3.2.
27
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
Toate bibliotecile de care vom avea nevoie în viitor, de exemplu, dinput.lib pentru lucru cu
dispozitive de intrare, vor fi adăugate la fel ca şi d3d9.1ib, nume fiind separate prin spaţiu.
Ordinea de scriere nu contează.
A doua metodă de conectare a bibliotecii necesare, constă în conectare implicită direct în fişierul
codului sursă, cu ajutorul directivei a preprocesorului pragma:
#pragma comment(lib, "d3d9.1ib")
Mai departe vom declara pointeri spre interfeţe necesare. Vom declara pointeri prin variabile
globale. Imediat după conectarea fişierelor antet, scriem:
LPDIRECT3D9 pDirect3D=NULL;
Acesta va fi pointerul spre interfaţa principală IDirect3D9, care ne va asigura lucrul cu grafica
3D. Am declarat o variabilă în care vom păstra adresa obiectului de interfaţă, vom numi-o
pointerul la interfaţă. La toţi pointeri trebuie să atribuim valoarea iniţială NULL.
În general, etapa de iniţializare a Direct3D 9 poate fi divizată în trei părţi. Mai întâi creăm un
obiect Direct3D 9, apoi setăm parametrii de reprezentare pentru Direct3D 9 şi în sfârşit, pe baza
setărilor efectuate, creăm un dispozitiv Direct3D 9.
if(FAILED(pDirect3D->
GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &Display)))
return E_FAIL;
D3DPRESENT_PARAMETERS Direct3DParameter;
ZeroMemory(&Direct3DParameter, sizeof Direct3DParameter);
Direct3DParameter.Windowed=TRUE;
Direct3DParameter.SwapEffect=D3DSWAPEFFECT_DISCARD;
Direct3DParameter.BackBufferFormat=Display.Format;
if(FAILED(pDirect3D->
CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hvnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&Direct3DParameter, &pDirect3DDevice)))
return E_FAIL;
/* или
if(FAILED(pDirect3D->
CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hvnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&Direct3DParameter, &pDirect3DDevice)))
return E_FAIL;
*/
return S_OK;
}
29
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
În linia:
if((pDirect3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
Apoi, trebuie să obţinem informaţii despre modul curent de vizualizare al monitorului. Anume,
rezoluţie a ecranului, colorare, formatul suprafeţei de vizualizare. Informaţiile acestea vor fi
folosite pentru a copia setările curente în buffer-ul din spate (back buffer). În Direct3D tot ceea
ce se vizualizează pe ecran, mai întâi se desenează în buffer-ul din spate, după ce se copie în
buffer-ul primar (front buffer), adică nemijlocit pe ecran. Procesul acesta se numeşte bufferizare
dublă. Permanent se face redesenarea buffer-ului din spate cu copierea ulterioară pe ecran al
monitorului, ceea ce permite crearea animaţia reală a obiectelor. În linia
D3DDISPLAYMODE Display;
D3DFMT_R8G8B8 = 20,
D3DFMT_A8R8G8B8 = 21,
D3DFMT_X8R8G8B8 = 22,
D3DFMT_R5G6B5 = 23,
D3DFMT_X1R5G5B5 = 24,
30
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
D3DFMT_A1R5G5B5 = 25,
D3DFMT_A4R4G4B4 = 26,
D3DFMT_R3G3B2 = 27,
D3DFMT_A8 = 28,
D3DFMT_A8R3G3B2 = 29,
D3DFMT_X4R4G4B4 = 30,
D3DFMT_A2B10G10R10 = 31,
D3DFMT_A8B8G8R8 = 32,
D3DFMT_X8B8G8R8 = 33,
D3DFMT_G16R16 = 34,
D3DFMT_A2R10G10B10 = 35,
D3DFMT_A16B16G16R16 = 36,
D3DFMT_A8P8 = 40,
D3DFMT_P8 = 41,
D3DFMT_L8 = 50,
D3DFMT_A8L8 = 51,
D3DFMT_A4L4 = 52,
D3DFMT_V8U8 = 60,
D3DFMT_L6V5U5 = 61,
D3DFMT_X8L8V8U8 = 62,
D3DFMT_Q8W8V8U8 = 63,
D3DFMT_V16U16 = 64,
D3DFMT_A2W10V10U10 = 67,
D3DFMT_D16_LOCKABLE = 70,
D3DFMT_D32 = 71,
D3DFMT_D15S1 = 73,
D3DFMT_D24S8 = 75,
D3DFMT_D24X8 = 77,
D3DFMT_D24X4S4 = 79,
D3DFMT_D16 = 80,
D3DFMT_D32F_LOCKABLE = 82,
D3DFMT_D24FS8 = 83,
31
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
#if !defined(D3D_DISABLE_9EX)
D3DFMT_D32_LOCKABLE = 84,
D3DFMT_S8_LOCKABLE = 85,
#endif // !D3D_DISABLE_9EX
D3DFMT_L16 = 81,
D3DFMT_VERTEXDATA =100,
D3DFMT_INDEX16 =101,
D3DFMT_INDEX32 =102,
D3DFMT_Q16W16V16U16 =110,
D3DFMT_MULTI2_ARGB8 = MAKEFOURCC('M','E','T','1'),
D3DFMT_R16F = 111,
D3DFMT_G16R16F = 112,
D3DFMT_A16B16G16R16F = 113,
D3DFMT_R32F = 114,
D3DFMT_G32R32F = 115,
D3DFMT_A32B32G32R32F = 116,
D3DFMT_CxV8U8 = 117,
#if !defined(D3D_DISABLE_9EX)
D3DFMT_A1 = 118,
D3DFMT_A2B10G10R10_XR_BIAS = 119,
D3DFMT_BINARYBUFFER = 199,
#endif // !D3D_DISABLE_9EX
D3DFMT_FORCE_DWORD =0x7fffffff
} D3DFORMAT;
pMode — pointerul la structura de tipul DISPLAYMODE, în cazul nostru este Display, care se
umple cu informaţii ce descriu modul curent al adapterului.
Următoarea linie:
ZeroMemory(&Direct3DParameter, sizeof Direct3DParameter);
curăţă de diferite "gunoaie" structura care se creează. Aici am folosit funcţia ZeroMemory().
Prim parametru (&Direct3DParameter) reprezintă o referinţă la structura parametrilor de
prezentare, care se curăţă. Al doilea parametru (sizeof Direct3DParameter) descrie
dimensiunea în octeţi a zonei care se curăţă, în cazul nostru toate câmpurile ale structurii. Antetul
funcţiei ZeroMemory()arată astfel:
33
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
VOID ZeroMemory(
PVOID Destination;
SIZE_T Length);
Apoi, în procesul de dezvoltare a proiectului, vom iniţializa câmpuri noi, mărind posibilităţile
aplicaţiei.
Windowed — caracterizează modul video, folosit de aplicaţia noastră. Valoarea TRUE indică
modul fereastră. La momentul de faţă folosim anume acest mod, în proiectul precedent au
fost setate dimensiunile ferestrei — 500x400 pixeli. FALSE — este modul fullscreen, adică pe
ecranul întreg;
Mai departe vom crea un obiect de interfaţă cu dispozitivul de vizualizare. Pentru asta vom folosi
funcţia CreateDevice(). Ne amintim că interfaţa principală IDirect3D9 se creează cu
funcţia Direct3DCreate9(), iar interfaţă a dispozitivului Direct3D 9 — cu funcţia
IDirect3DDevice9::CreateDevice(). Acestea două funcţii sunt absolut. Funcţia
CreateDevice()are următorul antet:
HRESULT CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
35
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface
)
D3DDEVTYPE_FORCE_DWORD — nu se foloseşte;
36
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
În principiul, ambele macrouri lucrează după o schemă asemănătoare. Totuşi este şi diferenţa.
Cercetăm aceste macrouri.
Al doilea macrou:
37
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
if(SUCCEEDED(...))
Totul este bine, mergem mai departe
else
Eşuare
Rendering-ul reprezintă procesul de desenare a obiectelor 3D. Pentru început, vom colora buffer-
ul din urmă cu o culoare oarecare, doar uniform.
În primul rând vom curăţa buffer-ul din urmă. Pentru asta vom folosi funcţia
IDirect3DDevice9::Clear()care are următorul antet:
HRESULT Clear(
DWORD Count,
const D3DRECT *pRects,
DWORD Flags,
D3DCOLOR Color,
float Z,
DWORD Stencil
)
Count — numărul de regiuni dreptunghiulare, care trebuie să fie curăţate. Regiunile sunt date
printr-un vector de dreptunghiuri (parametrul 2). Dacă se indică valoarea 0, se va curăţa toată
suprafaţa, adică toată regiunea de randare;
pRects — adresa vectorului de dreptunghiuri. Fiecare element al acestui vector este structura
de tipul D3DRECT, care descrie dimensiunile unei zone dreptunghiulare. Declararea tipului
structurat D3DRECT este următoarea:
typedef struct _D3DRECT {
LONG x1;
LONG y1;
LONG x2;
38
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
LONG y2;
} D3DRECT;
Flags — indică care din suprafeţele trebuie să fie curăţate. Valoarea parametrului reprezintă
o combinaţie arbitrară a următoarelor flaguri:
Color — culoare. Pentru a seta valoarea parametrului acesta putem utiliza macroul
D3DCOLOR_XRGB(). De exemplu, D3DCOLOR_XRGB(255, 255, 50) va colora regiunea
de randare cu galben deschis;
Z — indică valoarea pentru curăţare a Z-bufferului. Valoarea trebuie luată din intervalul
[0.0f — 1.0f]. Valoarea 0.0f — reprezintă cea mai apropiată distanţă de la observator.
Valoarea 1.0f — reprezintă cea mai îndepărtată distanţă de la observator. Deocamdată vom
folosi valoarea 1.0f. Sensul parametrul mai detaliat va fi descris în compartimenul
consacrat bufferului de adâncime;
Stencil — valoarea pentru curăţare a bufferului de şablon. Trebuie luată din intervalul de la
0 până la 2n-1, unde n este adâncime în biţi a bufferului de şablon. Deocamdată vom pune
parametrul acesta pe 0. Mai detaliat parametrul acesta va fi descris ulterior.
Deci, ştiind valorile necesare ale argumentelor funcţiei Clear(), putem să curăţim buffer-ul din
urmă:
pDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(255, 255, 0), 1.f, 0);
În Direct3D se foloseşte noţiunea de scenă (engl. scene). În scenă întră toate obiectele 3D cu
toate şi diferite proprietăţile sale. Înainte de chemarea scenei se apelează funcţia BeginScene()
din interfaţa IDirect3DDevice9. Funcţia BeginScene()semnalează că poate fi începută
randarea obiectelor scenei, adică elaborează comanda de desenare a scenei:
pDirect3DDevice->BeginScene(); // începutul scenei
Ambele funcţii nu au parametri. Fiindcă, deocamdată nu avem scenă (pur şi simplu scena este
goală), între aceste două apeluri nu este nimic, totuşi după fiecare apel al funcţiei
BeginScene() neapărat trebuie să fie apelul EndScene(), iar între aceste două apeluri are loc
randarea scenei.
Acum totul ce a fost desenat în buffer-ul din urmă (back buffer), vom afişa pe ecran cu ajutorul
funcţiei IDirect3DDevice9::Present(). Ea va copia ceia ce a fost desenat din buffer-ul din
urmă în bufferul frontal (front buffer), adică pe ecran. Antetul funcţiei de prezentare este
următorul:
HRESULT Present(
const RECT *pSourceRect,
const RECT *pDestRect,
HWND hDestWindowOverride,
const RGNDATA *pDirtyRegion
)
pDirect3DDevice->BeginScene();
// Aici va urma desenarea scenei
pDirect3DDevice->EndScene();
40
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
return S_OK;
}
După crearea funcţiei care va face renderingul, apelul ei plasăm în prelucrarea cozii în funcţia
MainWinProc() în locul unde se face redesenarea ferestrei:
case WM_PAINT:
RenderingDirect3D();
ValidateRect(hwnd, NULL);
return 0;
În procesul de închidere a aplicaţiei, ultima trebuie să întoarcă toate resursele ale sistemului
ocupate de către Direct3D 9. Conform regulilor de utilizare a СОМ-interfeţelor, toate resursele
trebuie descărcate din memorie iar referinţele respective trebuie puse pe zero. Pentru asta avem
la dispoziţie funcţia Release(), care deja a fost descrisă. Trebuie să ţinem cont de ordine de
eliberare a resurselor (obiectelor). Eliberarea se face în ordinea inversă cu ocupare a lor. Ultima a
fost declarată interfaţa pDirect3DDevice9, deci ea va fi eliberată prima. Etc., în ordinea
inversă.
Pentru asta scriem funcţia, pe care vom numi-o DeleteDirect3D(), şi care va elibera
resursele ocupate:
void DeleteDirect3D()
{
if(pDirect3DDevice)
pDirect3DDevice->Release();
if(pDirect3D)
pDirect3D->Release();
}
Textul programului actual este dat în anexa 1, ia rezultatul programului este arătat în fig. 3.3.
41
Grafica 3D (Suport de curs în baza Direct3D), S.Pereteatcu, A.Pereteatcu
42