\\ Home : Articoli : Stampa
Inizializzazione
Di RobyDx (del 14/01/2007 @ 16:59:00, in DirectX9, linkato 8933 volte)

Benvenuti al primo tutorial su DirectX9, la prima libreria grafica con supporto diretto per la piattaforma NET di Microsoft. Questo significa che ciò che imparete in questi tutorial potrà facilmente essere tradotto su tutti i linguaggi .Net. Direct3D è una delle librerie di DirectX9, quella dedicata alla gestione della grafica 3D. Tramite Direct3D le applicazioni interagiscono direttamente con il sistema ed in particolare con la scheda video del Pc ottenendo una situazione ideale per disegnare ad alta velocità ambienti grafici, cosa difficilmente ottenibile tramite l’interfaccia grafica di Windows, non adatta per questo tipo di applicazioni. Direct3D comprende una serie di oggetti che una volta creati prendono il controllo delle risorse grafiche del PC: usare DirectX significa saper creare questi oggetti e saperli gestire in modo appropriato. In particolare ogni applicazione DirectX ha bisogno di una inizializzazione. Se avete notato VB crea automaticamente il codice per inizializzare Form e controlli lasciando a noi solo la ‘fatica’ di posizionarli tramite editor grafici. In DirectX questo è invece compito nostro.

Per una migliore visualizzazione cambiate la proprietà FormBorderStyle della finestra in FixedSingle e impostate su false MaximizeBox e MinimazeBox ma non è fondamentale.

Riferimenti

Dando per scontato che DirectX9 è installato nei vostri PC create una nuova applicazione Windows tramite Visual Basic. Ora è necessario aggiungere i riferimenti a DirectX, ossia aggiungere un collegamento alle librerie DirectX in modo da poterle utilizzare. Andate al menù progetto e da lì cliccate aggiungi riferimenti. Vi comparirà questa finestra

riferimenti librerie directx visual studio

Nella sezione .Net troverete dei componenti Microsoft.DirectX che comprendono tutte le librerie. Per la grafica 3D sono sufficienti la classe base DirectX e le sue derivate Direct3D e Direct3DX. Quest’ultima è una classe di supporto che contiene molte utilità per la gestione D3D. Sceglietele, selezionatele e premete OK. I riferimenti sono aggiunti. Per poter utilizzare i componenti è più comodi usare l’istruzione imports ovunque venga utilizzato un componente DirectX in modo da risparmiarvi molto codice inutile. Quindi in cima ad ogni modulo inserite

Imports Microsoft.DirectX

Imports Microsoft.DirectX.Direct3D

In questo modo invece di dover scrivere ad esempio Microsoft.DirectX.Device per indicare un componente basterà scrivere Device.

Inizializzazione

Ora creeremo una routine per la creazione di un oggetto Device. Un Device è un oggetto che controlla direttamente lo schermo ed è quello più importante. Una volta creato il Device l’applicazione sarà direttamente collegata al sistema e ne avrà il controllo. Dichiarate quindi in un modulo, nel form, insomma in modo che sia visibile ovunque vi serva, un oggetto device. Io preferisco creare un modulo standard ed inserire al suo interno tutte le funzioni di inizializzazione degli oggetti DirectX, come ricorderanno tutti quelli che hanno letto i miei tutorial su DirectX8. Scrivete:

Public device As Device

Come ho detto il device controlla la grafica DirectX e quindi al momento della creazione dell’oggetto avverranno delle modifiche al video più o meno profonde. I giochi a cui voi normalmente giocate possono essere infatti in una finestra (Windowed mode) o a schermo pieno facendo scomparire le finestre e la barra di avvio di windows (Full Screen mode). Per il fullscreen inoltre è possibile settare una risoluzione (tutti i giochi lo permettono). Tutte le caratteristiche per la creazione di un device vengono inserite in un oggetto presentParameters.

Dim settaggio As New PresentParameters()

Questo oggetto comprende numerose proprietà di settaggio, alcune comuni sia al fullscreen che al

windowed mode, altre dedicate alle singole modalità.

Per una impostazione in finestra un possibile settaggio è il seguente

settaggio.BackBufferCount = 1 'numero backbuffer

settaggio.AutoDepthStencilFormat = DepthFormat.D16 'formato Z/Stencil

settaggio.EnableAutoDepthStencil = True 'ZStencil buffer attivato

settaggio.DeviceWindowHandle = fhWnd 'handle del form

settaggio.SwapEffect = SwapEffect.Flip 'tipo di renderizzazione

settaggio.Windowed = True 'settaggio per finestra

Mentre per un fullscreen con risoluzione di colore 800 x 600 a 32Bit di colore

settaggio.BackBufferCount = 1 'numero backbuffer

settaggio.AutoDepthStencilFormat = DepthFormat.D16 'formato ZStencil

settaggio.EnableAutoDepthStencil = True 'ZStencil buffer attivato

settaggio.DeviceWindowHandle = fhWnd 'handle del form

settaggio.SwapEffect = SwapEffect.Flip 'tipo di renderizzazione

settaggio.Windowed = False 'settaggio per fullscreen

settaggio.BackBufferWidth = 800 'risoluzione schermo

settaggio.BackBufferHeight = 600 'risoluzione schermo

settaggio.BackBufferFormat = Format.X8R8G8B8 'formato colore a 32

Decidete uno dei due settaggi (poi vi spiegherò tutto in dettaglio).

Ora spieghiamo a cosa serve ogni proprietà. Sembra noioso ma è l’unico modo per capire cosa fa ogni componente.

BackBufferCount: In una applicazione grafica tutte le immagini (sia 2D che 3D) vengono disegnate su un particolare ‘Foglio’ chiamato backbuffer. Questo è una zona di memoria della scheda video in cui viene tenuta in memoria l’immagine. Quando sono finite tutte le operazioni di disegno il backbuffer viene dato al primary buffer e quindi mostrato sullo schermo. Di solito si ha solo 1 backbuffer ma a volte se ne possono specificare più di uno in modo da aumentare la velocità della grafica a dispendio della memoria video. Ogni scheda video supporta un certo numero di backbuffer. Di solito 1 o 2 sono le migliori a secondo delle schede.

AutoDepthStencilFormat: il depth stencil buffer è una zona di memoria simile al backbuffer ma responsabile della rappresentazione di alcune informazioni tra cui ad esempio la profondità degli oggetti 3D. Questa superficie serve per poter usare lo Z buffer, fondamentale per la grafica 3D. Il formato più supportato è D16 (16 bit per il depth) ma molte schede ne supportano altre come D32 (32bit) o anche D24X8, o anche D24S8 (8bit usati per lo stencil e 24 per il depth). Al momento settatelo così, poi nei prossimi tutorial lo vedremo in dettaglio.

EnableAutoDepthStencil: Se lo impostate su true attivate il depthStencil buffer altrimenti non viene creato (lasciatelo su true o non potrete usare il 3D).

DeviceWindowHandle: Fondamentale!!! L’handle è un puntatore ad un controllo(oggetto di tipo System.IntPtr). DirectX, anche quando è a pieno schermo, ha bisogno di un oggetto di riferimento (in genere un form ma anche un pixturebox va bene) per la sua gestione. Gli handle sono degli identificativi che il sistema operativo assegna ad ogni finestra o controllo e cambiano ad ogni avvio. Dovete assegnare all’oggetto FhWnd di tipo System.IntPtr (o anche direttamente alla proprietà) la proprietà handle del form che usate (Me.Handle dall’interno della classe form o Form1.ActiveForm.Handle() dall’esterno). Per questo trovo più comodo passarglielo tramite oggetto.

SwapEffect: Modalità video dell’applicazione, ne esistono 3 SwapEffect.Copy, SwapEffect.Discard o SwapEffect.Flip. Per dare una rapida classificazione copy è usato per un solo backbuffer ed è il più lento, Flip è in genere il migliore e applicabile a più backbuffer mentre discard si usa solo per alcune modalità di antialiasing (nei prossimi tutorial).

Windowed : Se settato a true esegue in finestra, altrimenti a pieno schermo

BackBufferWidth e BackBufferHeight: per settare la risoluzione dello schermo. Potete inserire solo le risoluzioni compatibili per la scheda video. Di solito quelle universali sono 640 x 480, 800 x 600, 1024 x 768. Per la modalità windowed lasciatele entrambe a zero.

BackBufferFormat: colore della risoluzione. Di solito possono essere usate 2 modalità: 32bit Format.X8R8G8B8 e 16 bit Format.R5G6B5. A 16 bit è più leggero ma 32 bit è migliore da vedere. Lasciate a zero anche questo in windowed mode.

Ci sono altre cose da settare ma fermiamoci qui. Forse l’unica ancora interessante è

PresentationInterval : se non lo spostate il video si sincronizzerà con il monitor (immagine perfetta ma ovviamente ogni secondo la fase finale di disegno fermerà il programma per attendere l’istante giusto). Quindi se ad esempio il monitor è a 75Hz massimo potrete visualizzare 75 fotogrammi al secondo anche se in realtà il programma potrebbe andare a 1000. Altri valori (compaiono automaticamente) servono per variare tale velocità. Il più utile è PresentInterval.Immediate, che farà andare al massimo l’applicazione ma non sarà bella da vedere, utile per test di velocità (se il gioco vi gira a 200 fotogrammi al secondo allora gira anche su sistemi più lenti).

Dopo tutto questo creiamo l’oggetto device.

Dato che esistono diverse versioni della stessa istruzione (modalità overload). Io uso questa

device = New device(0, DeviceType.Hardware, fhWnd, CreateFlags.SoftwareVertexProcessing, settaggio)

Zero indica il numero della scheda video. Zero è il default ma alcuni computer hanno più schede video da poter usare.

DeviceType è il tipo di modalità da usare. La migliore è la modalità hardware che sfrutta la scheda video. Una seconda possibilità è la reference che sfrutta solo il sistema. Questa modalità è lentissima ma è utile per una scheda che non supporta determinate caratteristiche. In questo modo potrete almeno testare caratteristiche non adatte alla vostra scheda video ma sarà lenta per farci grosse applicazioni.

FhWnd è uguale a DeviceWindowHandle usata per il settaggio.

CreateFlags imposta la modalità di gestione dei vertici, Hardware è la più veloce mentre software la più compatibile. C’è ne sono altre ma ora non ci interessano.

Settaggio è infine l’oggetto che abbiamo creato per settare il device. Ora il device è creato e se è pieno schermo vedrete che tutto è cambiato. Ora inizieremo ad usare il device.

Visualizzazione

Per chi usa Visual Basic la cosa sembra un po’ anomala. DirectX ha necessità di una struttura ciclica e iterativa, non ad eventi. Occorre quindi usare un ciclo infinito per visualizzare la grafica. Effettuate l’inizializzazione dal form_load (o semplicemente chiamate una funzione che lo fa dal form_load). Inizializzate e fate comparire il form con

Me.Show()

Me.Focus()

Il form altrimenti potrebbe non comparire e darvi qualche errore.

Ora create una routine che esegua la grafica.

Conviene creare un ciclo do loop che ciclicamente esegua le funzioni grafiche (nonché tutte le istruzioni quando vorrete creare un gioco). Ecco un ciclo valido

Sub mainLoop() Do ‘istruzioni grafiche e della applicazione Loop End Sub

Le fasi grafiche di una applicazione sono:

clear :pulisce lo schermo dai precedenti disegni

renderizzazione: tutte le istruzioni grafiche che scrivono sul backbuffer

presentazione: il backbuffer viene mostrato sullo schermo

Vengono tutte eseguite dal device o da oggetti che sono comunque collegati ad esso.

L’istruzione per pulire lo schermo è

device.Clear(ClearFlags.Target, colore, 1, 0)

Questa è solo una delle possibili forme della istruzione. In questo caso target serve a pulire lo schermo cancellando tutto quello che è presente nella finestra o nello schermo (a secondo della modalità). Colore è un oggetto di tipo System.Drawing.Color e serve per specificare il colore con cui verrà pulito lo schermo. Le altre opzioni verranno spiegate nei prossimi tutorial. Eseguendo questa istruzione con colore nero faranno in modo che la finestre o lo schermo intero diventi completamente nero. Semplice fin qui.

device.BeginScene()

device.EndScene()

Tra queste due istruzioni devono svolgersi tutte le fase di rendering e servono solo a preparare il device.

Infine quando tutto è disegnato

device.Present()

Fa comparire tutto sullo schermo.

Dato che tutta la grafica (e anche tutta l’applicazione) viene gestita da un ciclo occorre usare l’istruzione

Application.DoEvents()

In questo modo windows non penserà che l’applicazione sia bloccata e si potrà rispondere a degli eventi.

Per fermare l’applicazione servirà distruggere il device e terminare l’applicazione. Potete inventare mille modi per farla terminare. Io uso un end in risposta ad un evento KeyDown (tasto premuto) o form unload.

L'importante è comunque utilizzare l'istruzione

Device.Dispose()

Per chiudere nel migliore dei modi l'applicazione.

Eseguite l’applicazione e a secondo di come avete impostato il device vedrete lo schermo o la finestra del colore che avete scelto. Questo è il tutorial più importante e anche il più lungo ma dai prossimi tutorial cominceremo ad usare i primi concetti di grafica 3D e di enumerazioni, ossia la capacità di interrogare la scheda video per verificare le sue potenzialità. Vi lascio il primo esempio di inizializzazione di DirectX che vi permette di generare una finestra o un fullscreen e cambiare colore con i tasti da 1 a 0. 

 
Qui invece trovate l'esempio aggiornato a .Net 2.0 e C#. Ci sono delle leggere differenze. La principale è il ciclo di rendering che si basa sull'evento Paint, continuamente invocato utilizzando l'istruzione invalidate. Potete usarlo anche in VB o usare il ciclo che preferite (consiglio il metodo Paint)