Sei sulla pagina 1di 27

Che cosa si intende per inizializzazione?

Per chi non ha utilizzato altri linguaggi (C o Java) sappiate


che la cosa pi bella di VB il non dover scrivere una riga di codice per far comparire finestre e
pulsanti che altrimenti richiederebbero pagine di istruzioni. Per Dx per dobbiamo spendere del
codice per preparare il computer alle operazioni di disegno.Questa la parte pi complicata e
difficile da ricordare ma per fortuna pu essere fatta una volta sola nella vita perch una volta creata
la propria routine di inizializzazione si potr usare sempre quella con poche modifiche.Bene
iniziamo. Per prima cosa dovete selezionare la Dll di directX8 : andate nel menu progetto e da l a
riferimenti e vi apparir questa finestra

Dopo aver selezionato la libreria DirectX8 schiacciate Ok e tornate al codice.


Un programma che usa Dx si compone di tre fasi:
1) Inizializzazione ossia tutto il codice che prepara il Pc al rendering
2) Il rendering ossia tutta la fase di disegno
3) Chiusura.
Inizializzazioni
Nel codice del form (se non l'ho detto d per scontato che sappiate usare bene VB perch se siete
alle prime armi cambiate sito) inserite le seguenti variabili
Dim DX As New DirectX8
Dim D3D As Direct3D8
Dim device As Direct3DDevice8
e alla funzione Form_Load inserite questo
Private Sub Form_Load()
Set D3D = DX.Direct3DCreate() 'crea D3d

Dim D3DWindow As D3DPRESENT_PARAMETERS 'descrive tutte le propriet dello schermo


'sistema tutte le propriet
D3DWindow.SwapEffect = D3DSWAPEFFECT_FLIP
D3DWindow.Windowed = 0
D3DWindow.BackBufferCount = 1
D3DWindow.BackBufferFormat = D3DFMT_R5G6B5 'bit di sistema
D3DWindow.BackBufferWidth = 800
D3DWindow.BackBufferHeight = 600
D3DWindow.hDeviceWindow = Me.hWnd
D3DWindow.EnableAutoDepthStencil = 1
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16 '16 bit Z-Buffer
'crea device
Set device = D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd,_
D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DWindow)
Form1.Show
Call mainLoop
End Sub
Non avete capito , pazienza! No scherzo ora ve lo spiego nel dettaglio.
Le variabili
Dim DX As New DirectX8 'con questa riga creo l'oggetto directX8 che praticamente una insieme
di funzioni che permettono di creare tutti gli altri oggetti
Dim D3D As Direct3D8 'questo oggetto serve alla creazione e gestione della grafica 3D in DirectX8
Dim device As Direct3DDevice8 'questo oggetto lo si pu immaginare come un controllo dello
schermo. Il 99% delle operazioni di disegno sono svolte da questo oggetto
Il Codice
Private Sub Form_Load()
Set D3D = DX.Direct3DCreate() 'in questa fase creo l'oggetto D3D da quello Dx (che creato nelle
variabili). Il sistema lo prepara automaticamente e da questo momento pronto)
Dim D3DWindow As D3DPRESENT_PARAMETERS 'questa variabile raggruppa tutte le propriet
dello schermo. Se avete in mente tutti i giochi per Pc vi sarete accorti che ognuno si gestisce lo
schermo come crede: si passa da quelli in finestra a quelli a pieno schermo con tutte le risoluzioni
possibili ed immaginabili.In questo esempio sto regolando le opzioni per un FullScreenMode
(modalit a pieno schermo) con risoluzione 800 x 600 con 16Bit di colore (65256)
D3DWindow.SwapEffect = D3DSWAPEFFECT_FLIP
D3DWindow.Windowed = 0
D3DWindow.BackBufferCount = 1
D3DWindow.BackBufferFormat = D3DFMT_R5G6B5 'bit di sistema
D3DWindow.BackBufferWidth = 800
D3DWindow.BackBufferHeight = 600
D3DWindow.hDeviceWindow = Me.hWnd
D3DWindow.EnableAutoDepthStencil = 1

D3DWindow.AutoDepthStencilFormat = D3DFMT_D16 '16 bit Z-Buffer


In queste righe ho inpostato tutte le opzioni per lo schermo.Ognuna delle componenti di
D3DWindow regola una opzione. Attenzione perch non potete regolarle a caso perch ognuna ha
regole precise. In fondo alla lezione ve le spiego tutte.
'crea device
Set device = D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DWindow) 'Questa lunga riga crea
l'oggetto destinato ad operare tutte le operazioni grafiche di DirectX8: il device. Ognuna degli
argomenti ha un significato che ora vi elenco:
D3DADAPTER_DEFAULT indica che abbiamo intenzione di usare la scheda video principale del
computer. Salvo pochi computer in genere esiste una sola scheda video ma se siete fortunati potreste
averne due e quindi potreste dargli un argomento diverso chiamato Guid (argomento della prossima
lezione).
D3DDEVTYPE_HAL indica che desiderate utilizzare la accellerazione video di sistema. Questa
offre la massima prestazione. Un altro argomento D3DDEVTYPE_REF ossia senza
accellerazione grafica utile se non si supporta DirectX ma troppo lento. Forse pu risultare utile per
programmi di grafica (3D studio un esempio)
Me.hWnd semplicemente il device contest della finestra. In breve ogni finestra ha un numero alla
sua partenza e bisogna darlo al sistema.Attenzione ho usato me perch il codice si trova nella
finestra che uso altrimenti si deve usare per esempio Form1 (il nome della finestra). Ps sembra
assurdo ma se gli date il Hwnd di un' altra finestra anche di un altro programma le immagini
appariranno l ma attenti, si possono verificare maree di problemi.
D3DCREATE_SOFTWARE_VERTEXPROCESSING un argomento che specifica dove le
trasformazioni dei poligoni avvengono. Si puo sostituire SOFTWARE con HARDWARE ma solo
pochissime schede supportano tale propriet. Se fosse cos siete fortunati, la velocit del vostro
gioco salir molto.
D3DWindow qui ho semplicemente passato la variabile precedentemente creata alla funzione.
Form1.Show 'a volte la finestra mi si riduce a icona, cos non accade
Call mainLoop 'qui chiamo la funzione che eseguir il disegno
End Sub
Il rendering
ecco la funzione di rendering
Sub mainLoop()
1
device.Clear 0, ByVal 0, D3DCLEAR_TARGET, D3DColorRGBA(0, 0, 0, 0), 1#, 0'pulisce lo schermo
device.BeginScene 'inizia il rendering
'tutto il codice che deve eseguire le varie fasi di rendering
'(ossia il disegno degli elementi 2D\3D va qui
device.EndScene 'fa terminare il rendering
device.Present ByVal 0, ByVal 0, 0, ByVal 0 'invia l'immagine al monitor
DoEvents
GoTo 1
End Sub

questa funzione chiamata dal Form1_Load esegue la prima operazione di disegno : crea uno
schermo nero. Anche se sembra sbagliato bisogna entrare in un loop infinito se volete creare un
gioco. In questo modo potete far girare centinaia di volte il codice. Ognuna di queste sar un
fotogramma (ecco cosa significa che un gioco gira a 30 Fps). Ricordate di inserire DoEvents che
serve ad avere sempre il controllo del programma (ad esempio per chiudere una finestra).
Passiamo al dettaglio.
device.Clear 0, ByVal 0, D3DCLEAR_TARGET, D3DColorRGBA(0, 0, 0, 0), 1#, 0 'questa
funzione pulisce tutto lo schermo rendendolo del colore espresso in D3DColorRGBA( cambiate i
numeri da 0 a 255 per modificare il colore). Per ora non vi spiego il resto ma vi anticipo che qui vi
una delle cose pi belle di DirectX8 : da qui si pu creare molto facilmente un gioco in SplitScreen
(ad esempio uno sparatutto in soggettiva con 4 persone che giocano sullo stesso schermo). Io ci
sono riuscito e poi ve lo spiegher.
device.BeginScene 'inizia il rendering
'tutto il codice che deve eseguire le varie fasi di rendering
'(ossia il disegno degli elementi 2D\3D va qui
device.EndScene 'fa terminare il rendering
device.Present ByVal 0, ByVal 0, 0, ByVal 0 'invia l'immagine al monitor anche qui le opzioni
permettono di decidere quale zona del nostro mondo 3D mandare in una zona dello schermo. In
questo caso le opzioni sono di default e inviano tutta la zona allo schermo.
DoEvents' per non far bloccare il PC
GoTo 1 (sapete come si adopera altrimenti leggetevi la guida)
Chiusura
Un programma Dx non si pu semplicemente chiudere, se lo fate vi potrebbe rimanere l'ultima
immagine sullo schermo o bloccarsi il computer. Per questo bisogna fare alcune cose.Aggiungete un
evento doppio click al form (questo codice).
Private Sub Form_DblClick()
'termina il programma
Set DX = Nothing
Set D3D = Nothing
Set device = Nothing
End
End Sub
Poich avete inserito l'istruzione DoEvents nel loop il form risponder all'evento ma per chiudere
definitivamente il programma bisogna inserire End in Form_DblClick. Appena farete doppio click
sullo schermo il programma si chiuder.
Fate partire il programma e lo schermo vi diventer completamente nero; no panic il programma
funziona cambiate i valori del colore nel device.Clear e lo schermo cambier colore.
Spero non sia stato difficile e che non mi sia dilungato troppo ma volevo essere chiaro il pi
possibile.Se non lo sono stato avvertitetimi e mi tagler le vene(neanche per sogno)!
Vi d un p di opzioni da modificare nel Load (FATE TANTI ESPERIMENTI SOLO COSI'

CAPIRETE IL MECCANISMO).
D3DWindow.SwapEffect = D3DSWAPEFFECT_FLIP
Lasciatela cos rappresenta solo il modo con cui l'immagine trasferita al monitor; questa l'
opzione pi compatibile
D3DWindow.Windowed = 0
Se gli date il valore 0 il programma va a pieno schermo. Se gli date invece il valore 1 andr in una
finestra. Per far ci dovete modificare un p di cose per.
D3DWindow.BackBufferCount = 1
Numero dei backbuffer : pi alto pi andr veloce a discapito della memoria video. Di solito si
usa 1 o 2 perch 3 non supportato da quasi nessuna scheda
D3DWindow.BackBufferFormat = D3DFMT_R5G6B5 'colore
Questa una costante che indica i bit della scheda video. Ce ne sono un' infinit molte delle quali
non supportate. Per vedere quanti bit sono dovete fare la somma dei numeri vicino al colore
(R5G6B5=16).
D3DWindow.BackBufferWidth = 800
D3DWindow.BackBufferHeight = 600
Semplicemente la risoluzione dello schermo in larghezza (800) e altezza(600).Potete dargli una
qualsiasi risoluzione valida. Le pi comuni sono 640x480 800x600 320x240 1024x768 ma in realt
ce ne sono un'infinit per ogni scheda.
D3DWindow.hDeviceWindow = Me.hWnd
qui dovete dargli la propriet hWnd del Form (la potete memorizzare anche in una variabile long)
D3DWindow.EnableAutoDepthStencil = 1
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16 '16 bit Z-Buffer
Queste lasciatele anche cos indicano solo il formato del Zbuffer (ne parlo dopo) potete provare con
D24 o D32 a seconda della scheda.
Attenzione se provate a cambiare alcune cose potrebbe darvi errori di automazione. LA COSA
NON DANNEGGIA IL PC MA IO NON MI RITENGO RESPONSABILE DI NESSUN DANNO,
tutte queste cose le ho trovate anche in altri siti e non mi hanno mai danneggiato niente (al
massimm si resetta il PC. Qui trovate il codice di esempio. Fatelo partire e chiudetelo con doppio
click.
L'enumerazione semplicemente una interrogazione del computer su ci che in grado di fare. Con
un programma di enumerazione potrete creare ad esempio una lista con le risoluzioni possibili o
sapere se la scheda supporta una determinata operazione. La cosa sembra noiosa ma fondamentale
perch non detto che un programma creato su un Pc giri su un altro. Se avrete una lista con le
capacit della scheda video di chi esegue il programma potrete far scegliere a chi lo usa la
risoluzione e le caratteristiche di visualizzazione. Questo il codice di un programma di
enumerazione che non fa partire lo schermo Dx. Sar vostro esercizio montare la cosa insieme
(ovviamente prima di far partire la prima schermata del gioco).

Caricate la libreria dal menu riferimenti come nel precedente esempio.Visualizzate il form e inserite
2 listBox come in figura

e aggiungete il seguente codice al form.


Dichiarate queste variabili
Dim dx As New DirectX8
Dim d3d As Direct3D8
Dim caps As D3DCAPS8
Le prime due le conoscete gi mentre nuova l'ultima. Il tipo D3DCAPS8 memorizza tutte le
capacit del computer e permette di ottenere i dati utili.
Nel Load inserite questo:
Private Sub Form_Load()
'crea il direct 3d
Set d3d = dx.Direct3DCreate
d3d.GetDeviceCaps D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, caps
'esempi di enumerazione della propriet caps
List2.AddItem caps.MaxTextureHeight & " massima altezza della Texture"
List2.AddItem caps.MaxTextureWidth & " massima larghezza della Texture"
'esempi di enumerazione con costanti
If caps.LineCaps And D3DLINECAPS_FOG Then

List2.AddItem "nebbia supportata"


Else
List2.AddItem "Nebbia non supportata"
End If
Call elenca
End Sub
Dopo aver creato l'oggetto D3D abbiamo usato la funzione getDeviceCaps di questa per
memorizzare tutte le caratteristiche della scheda nella variabile caps. Ora ci sono due metodi per
vedere le propriet della scheda :
1) nel caso si tratti di valori numerici basta assegnare ad una variabili (in genere di tipo long) il
valore dato da Caps. (punto) e il nome della propriet. Nei primo caso ho usato
caps.MaxTextureHeight per ottenere l'altezza massima per le texture e l'ho inserito nella lista due
con una semplice concatenazione di stringhe (simbolo &) per leggerlo meglio. Il secondo caso
equivalente semplicemente MaxTextureWidth restituisce il massimo valore per la larghezza dello
schermo. Il terzo caso differente. Per alcune propriet non c' un valore numerico ma solo un vero
o falso. In questi casi serve un if per vedere se la variabile caps vera per una determinata propriet
definita in una costante di Dx ad esempio usando caps.LineCaps And D3DLINECAPS_FOG questa
ci restituir vero se sono vere entrambe le cose (anche se come potete controllare non sono di tipo
Boolean).Ad esempio D3DLineCaps_Fog un componente della costante LineCaps (che vedete
anche in caps.LineCaps). In poche parole per vedere se una propriet vera dovete con un if vedere
se vero unire caps.(punto) una costante con una costante dello stesso gruppo. Se ad esempio
esistesse caps.colore e che esistesse una costante colore che include rosso,verde e blu per sapere se
si supporta il rosso dovrebbe restituire true caps.colore and rosso. Non chiedetemi di scrivere qui
tutte le costanti e propriet sono centinaia se non migliaia e non le conosco neanche tutte. Forse ne
far un elenco in seguito.
Ora descriviamo la sub Elenca che crea un elenco di tutte le risoluzioni supportate
Sub elenca()
Dim ModeTemp As D3DDISPLAYMODE 'questa variabili memorizza tutti i valori dello schermo
Dim nModes As Long
nModes = d3d.GetAdapterModeCount(0) 'riceve da D3d il numero di risoluzioni possibili
For I = 0 To nModes - 1 'esegue un ciclo che testa le risoluzioni
Call d3d.EnumAdapterModes(0, I, ModeTemp)
'Per ogni risoluzione esegue un test in base al colore
'la funzione check type restituisce un valore che se uguale a D3D_OK indica che
'la risoluzione valida
'list1.add semplicemente un istruzione che aggiunge il valore della risoluzione
'alla lista1
Select Case ModeTemp.Format
'32 bit
Case D3DFMT_X8R8G8B8

If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_


False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height & " 32 bit" &_
" [FMT: " & ModeTemp.Format & "]"
End If
'16 bit
Case D3DFMT_R5G6B5
If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_
False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height & " 16 bit" &_
" [FMT: " & ModeTemp.Format & "]"
End If
'16 bit bilanciato
Case D3DFMT_X1R5G5B5
If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_
False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height &_
" 16 bit bilanciato" & " [FMT: " & ModeTemp.Format & "]"
End If
'16 bit alpha
Case D3DFMT_D3DFMT_A1R5G5B5
If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_
False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height &_
" 16 bit alpha" & " [FMT: " & ModeTemp.Format & "]"
End If
'16 bit alpha bilanciato
Case D3DFMT_A4R4G4B4
If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_
False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height &_
" 16 bit alpha bilanciato" & " [FMT: " & ModeTemp.Format & "]"
End If
'16 bit x bilanciato
Case D3DFMT_X4R4G4B4
If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_
False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height &_
" 16 bit x bilanciato" & " [FMT: " & ModeTemp.Format & "]"
End If
'24 bit
Case D3DFMT_R8G8B8
If d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format,_
False) = D3D_OK Then
List1.AddItem ModeTemp.Width & "x" & ModeTemp.Height &_
" 24 bit" & " [FMT: " & ModeTemp.Format & "]"
End If
End Select
Next I

End Sub
In questa routine ho dichiarato una nuova variabile ModeTemp che memorizza le caratteristiche di
uno schermo (risoluzione, colore e fraquenza del monitor che non useremo). La prima cosa che
facciamo chiedere quanti tipi di risoluzioni abbiamo memorizzando in nModes (semplice variabile
numerica di tipo long) il valore dato da d3d.GetAdapterModeCount(0). Ora per con un ciclo FOR
controlliamo se ogni modalit supportata e se si la aggiungiamo alla lista ( per un vero gioco
potreste memorizzarle ed usarle ad esempio per il cambio di risoluzione. Per ogni risoluzione
memorizziamo i dati nella variabile modeTemp tramite l'istruzione
Call d3d.EnumAdapterModes(0, I, ModeTemp)
Quindi usiamo un select case in modo da selezionare solo i colori che ci interessano (le modalit si
trovano tramite costanti in ModeTemp.Format e per completezza ho inserito tutte le possibili nei
vari CASE). A questo punto se
d3d.CheckDeviceType(0, D3DDEVTYPE_HAL, ModeTemp.Format, ModeTemp.Format, False)
e uguale a D3D_OK allora la modalit supportata e l'aggiungiamo all'elenco List1. Il
checkDeviceType accetta vari opzioni : questi sono : 0 indica che si usa la scheda video principale;
D3DDEVTYPE_HAL indica che si vuole usare l'accellerazione grafica (D3DDEVTYPE_REF
indica senza accellerazione); ModeTemp.Format indica il colore e false indica che si usa la modalit
pieno schermo (con true si indica la modalit finestra). Una volta che questa funzione d come
risultato D3D_OK allora la risoluzione pu essere usata. Se volete potete usare il CheckDeviceType
anche soltanto per controllare una risoluzione assegnando da soli i valori a ModeTemp. Ora almeno
(per la risoluzione) potete creare un programma compatibile con tutte le schede video esistenti
baster controllare le varie risoluzioni e usare quella che interessa.
Finalmente cominciamo le cose serie: disegnare un oggetto 3D e farlo muovere nello spazio.
Scaricatevi subito il programma perch da ora in poi lavoriamo direttamente sul codice (che
comincer ad essere sempre pi lungo).In questo esempio creeremo un oggetto 3D (un cubo) e lo
faremo muovere in un ambiente 3D. Il cubo apparir bianco e senza ombre ma gi un importante
esempio perch tutto inizia da qui. Nel prossimo esempio lo coloreremo e vi aggiungeremo le
ombre. Attenzione la parte pi complicata questa, il resto sar fatto per aggiunte. Ricordate infine
che molte delle routine che spiego possono essere usate come codice fisso senza bisogno di
riscriverlo. Fra poco pubblicher il modulo mDx8a che contiene tutto un set di funzioni base per
ogni componente di directX. Ecco una miniatura del programma.

Innanzitutto la teoria. Uno schermo DirectX praticamente un immenso ambiente 3D impostabile


in ogni tipo di prospettiva. Gli oggetti posti al loro interno vengono posizionati con istruzioni di
disegno esattamente come in un piano cartesiano di cui per dobbiamo settare ogni cosa
dall'orientamento degli assi al punto di vista. Un possibile posizionamento del piano cartesiano
questo scelto da me.

Gli oggetti 3D , ad esempio i calciatori di un gioco di calcio 3d, sono formati da un insieme di
triangoli nello spazio chiamati poligoni. Maggiore sar il numero dei triangoli e meglio potr essere
rappresentato il nostro oggetto ma contemporaneamente aumentar il carico di lavoro per il PC. Se
ad esempio un quadrato formato da due triangoli allora ne serviranno 12 per rappresentare un
cubo che di 6 facce mentre per una sfera ne occorreranno moltissimi per far apparire le curve
meno spigolose possibili. In directX gli oggetti sono memorizzati in array di vertici (D3DVERTEX)
che letti in ordine ricreeranno il nostro disegno.Per il nostro cubo servono 12 triangoli e quindi 36
vertici.Il tipo D3DVERTEX composto da 8 valori : X,Y,Z che rappresentano le coordinate dei
punti nello spazio, TU e TV che rappresentano la posizione delle texture (prossima lezione),
Nx,Ny,Nz che rappresentano il modo in cui la luce si riflette sull'oggetto.Nel Form ho creato una
routine che crea il nostro cubo e nel modulo una funzione per modificarne pi facilmente i
valori.Osservate che nel form ho dichiarato un array cubo(35) di D3DVERTEX che memorizza i 36
vertici che ci servono(da 0 a 35). IMPORTANTE i punti che formano i triangoli devono essere
consecutivi( 0,1,2 il primo triangolo,3,4,5 il secondo e cos via..) e soprattutto disposti in senso
orario nell'ordine in cui vogliamo vederli; se li disponiamo in senso antiorario non compariranno se
non vedendoli da dietro. Per esempio se invertiamo l'ordine dei vertici dei triangoli vedremo solo le
parti interne del cubo non l'esterno. Una volta creato il nostro array per l'oggetto che vogliamo
rappresentare baster chiamare l'oggetto device.DrawPrimitiveUp e passargli il nostro array per
veder comparire il nostro cubo. Ma dove comparir il cubo?. I vertici che impostiamo rappresentano
solo la posizione di partenza dell'oggetto : saremo noi a specificare il punto esatto in cui devono
trovarsi i vertici dell'oggetto nonch la grandezza e la rotazione. Per far cio usiamo un'altra variabile
definita come D3DMATRIX. Per chi non conoscesse le matrici aritmetiche una matrice una
griglia di numeri che in DX formata da 16 valori disposti su 4 file. Solo intervendo su questi
valori si possono modificare posizione, scala e rotazione di oggetti e telecamere. Intervenire
direttamente sui 16 valori difficilissimo ma per fortuna Dx offre varie istruzioni che ci aiutano.
Ora veniamo al codice.
Codice
Il codice, ora che inizia a diventare pi lungo diviso in un modulo contenente istruzioni che si
possono definire una volta sola (come l'istruzione che crea lo schermo o lo chiude) e nel classico
form che contiene il codice di controllo del programma.
Il Modulo
Qui scrivo tutto ci che c' nel modulo che ho denominato mdx8.
'parte grafica
Global DX As New DirectX8
Global D3DX As New D3DX8
'////////////////////////////////
'//////PARTE GRAFICA////////////
'//////////////////////////////
Global D3D As Direct3D8 'direct 3d
Global device As Direct3DDevice8 'spazio in cui si rappresenta
Global dSprite As D3DXSprite 'gestisce gli sprite
Global matWorld As D3DMATRIX 'rappresenta il mondo
Global matView As D3DMATRIX 'rappresenta la camera
Global matProj As D3DMATRIX 'rappresenta come la camera rappresenta il mondo
Const rad1 = 3.14 / 180 'il pi greco
Sub CreaSchermo(dxWidth As Long, dxHeight As Long, Fhwnd As Long)

'qui si crea lo schermo


Dim D3DWindow As D3DPRESENT_PARAMETERS 'descrive la vista
Set D3D = DX.Direct3DCreate() 'crea D3d
'imposto le variabili di creazione dello schermo( lezione uno)
D3DWindow.SwapEffect = D3DSWAPEFFECT_FLIP
D3DWindow.BackBufferCount = 1
D3DWindow.BackBufferFormat = D3DFMT_R5G6B5 'colore
D3DWindow.BackBufferWidth = dxWidth
D3DWindow.BackBufferHeight = dxHeight
D3DWindow.hDeviceWindow = Fhwnd 'propriet hwnd della finestra rischiesta nel codice
D3DWindow.EnableAutoDepthStencil = 1
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16 '16 bit Z-Buffer
'crea device
Set device = D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Fhwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DWindow)
'Fino a qui rimasto tutto uguale queste ultime righe di codice sono la novit
'setta il tipo di vertice
device.SetVertexShader D3DFVF_VERTEX Or D3DFVF_TEX1
'disattiva la luce
device.SetRenderState D3DRS_LIGHTING, 0
device.SetRenderState D3DRS_SHADEMODE, D3DSHADE_GOURAUD
'attiva lo z buffer
device.SetRenderState D3DRS_ZENABLE, 1
'qualit texture
device.SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR
device.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR
'crea il controllo 2D
Set dSprite = D3DX.CreateSprite(device)
' The World Matrix
D3DXMatrixIdentity matWorld
device.SetTransform D3DTS_WORLD, matWorld
'The View Matrix
D3DXMatrixLookAtLH matView, MakeVector(0, 0, -30), MakeVector(0, 0, 0), MakeVector(0, 1, 0)
device.SetTransform D3DTS_VIEW, matView
'The projection Matrix
D3DXMatrixPerspectiveFovLH matProj, 45 * rad1, 1, 1, 1000
device.SetTransform D3DTS_PROJECTION, matProj
End Sub
Public Sub muoviObj(scalaX As Single, scalaY As Single, scalaZ As Single, angleX As Long, angleY As
Long, angleZ As Long, posX As Single, posY As Single, posZ As Single)
Dim CosRx As Single, CosRy As Single, CosRz As Single
Dim SinRx As Single, SinRy As Single, SinRz As Single

Dim mat1 As D3DMATRIX


rad = 3.14 / 180
CosRx = Cos(angleX * rad) 'Used 6x
CosRy = Cos(angleY * rad) 'Used 4x
CosRz = Cos(angleZ * rad) 'Used 4x
SinRx = Sin(angleX * rad) 'Used 5x
SinRy = Sin(angleY * rad) 'Used 5x
SinRz = Sin(angleZ * rad) 'Used 5x
With mat1
.m11 = (scalaX * CosRy * CosRz)
.m12 = (scalaX * CosRy * SinRz)
.m13 = -(scalaX * SinRy)
.m21 = -(scalaY * CosRx * SinRz) + (scalaY * SinRx * SinRy * CosRz)
.m22 = (scalaY * CosRx * CosRz) + (scalaY * SinRx * SinRy * SinRz)
.m23 = (scalaY * SinRx * CosRy)
.m31 = (scalaZ * SinRx * SinRz) + (scalaZ * CosRx * SinRy * CosRz)
.m32 = -(scalaZ * SinRx * CosRz) + (scalaZ * CosRx * SinRy * SinRz)
.m33 = (scalaZ * CosRx * CosRy)
.m41 = posX
.m42 = posY
.m43 = posZ
.m44 = 1#
End With
device.SetTransform D3DTS_WORLD, mat1
End Sub
'crea il vettore
Function MakeVector(x As Single, y As Single, z As Single) As D3DVECTOR
MakeVector.x = x
MakeVector.y = y
MakeVector.z = z
End Function
'crea il vertice
Function CreaD3Dv(x As Single, y As Single, z As Single, nx As Single, ny As Single, nz As Single, tu As
Single, tv As Single) As D3DVERTEX
CreaD3Dv.x = x
CreaD3Dv.y = y
CreaD3Dv.z = z
CreaD3Dv.tu = tu
CreaD3Dv.tv = tv
CreaD3Dv.nx = nx
CreaD3Dv.ny = ny
CreaD3Dv.nz = nz
End Function

Sub termina(Optional spegni As Boolean = True)


Set DX = Nothing
Set D3D = Nothing
Set device = Nothing
Set dSprite = Nothing
If spegni Then End
End Sub
Come vedete molto pi lungo e comprende nuove funzioni. Iniziamo dal creaSchermo. Fino al
punto in cui si crea il device il codice rimasto identico. Dopo noterete altro codice. L'istruzione
'setta il tipo di vertice
device.SetVertexShader D3DFVF_VERTEX Or D3DFVF_TEX1
imposta il tipo di vertice che vogliamo usare (in questo caso D3DFVF_VERTEX indica i vertici
standard e D3DFVF_TEX1 che vogliamo permettere di applicare le texture).NB che alcuni
istruzioni accettano di ricevere pi valori concatenati da OR.
'disattiva la luce
device.SetRenderState D3DRS_LIGHTING, 0
device.SetRenderState D3DRS_SHADEMODE, D3DSHADE_GOURAUD
'attiva lo z buffer
device.SetRenderState D3DRS_ZENABLE, 1
'qualit texture
device.SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR
device.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR
'crea il controllo 2D
Set dSprite = D3DX.CreateSprite(device)
Questa serie di istruzioni inpostano alcuni valori sulle luce e le ombre mentre Set dSprite crea il
controllo della grafica 2D. In questo caso ho disattivato la luce, inpostato le ombre su GOURAUD
mode, e ho inpostato la qualit delle texture su Linear. Osservate il D3DRS_ZENABLE, inpostando
come acceso (1), si dichiara che il pc attiver una zona di memoria per le profondit degli oggetti.
Se si inposta su spento (0) gli oggetti non saranno disegnati secondo la giust profondit ma un
oggetto ad esempio dietro ad un muro gli passer davanti se disegnato dopo. Quindi una istruzione
molto importante per la grafica 3D. NB passando il valore 0 voi disattivate l'opzione mentre con 1
la attivate (potete usare anche TRUE E FALSE ma io preferisco cos).
Le istruzioni successive impostano il nostro ambiente tramite le tre variabili definite in cima al
modulo
Global matWorld As D3DMATRIX 'rappresenta il mondo
Global matView As D3DMATRIX 'rappresenta la camera
Global matProj As D3DMATRIX 'rappresenta come la camera rappresenta il mondo
La prima usata nell'istruzione
D3DXMatrixIdentity matWorld
device.SetTransform D3DTS_WORLD, matWorld
serve ad azzerare la posizione degli oggetti come iniziale. D3DXMatrixIdentity assegna alla
variabile matWorld il volore di matrice identit (tutti zero tranne sulla diagonale in cui tutti i valori

sono uno).device.SetTransform imposta come il prossimo oggetto sar disegnato (attenzione si


user sempre questa istruzione per dire a Dx dove disegnare un oggetto).
La seconda
'The View Matrix
D3DXMatrixLookAtLH matView, MakeVector(0, 0, -30), MakeVector(0, 0, 0), MakeVector(0, 1, 0)
device.SetTransform D3DTS_VIEW, matView
inposta il punto di osservazione (posizione della telecamera). Come prima la prima istruzione una
utility di DX mentre la seconda l'assegnazione. Notate per che nella prima istruzione abbiamo
usato un'altra istruzione che ho creato
'crea il vettore
Function MakeVector(x As Single, y As Single, z As Single) As D3DVECTOR
MakeVector.x = x
MakeVector.y = y
MakeVector.z = z
End Function
Questa serve per iniziare pi facilmente una variabile D3DVECTOR che memorizza tre valori
X,Y,Z di tipo single (usati spesso se si vuole controllare la telecamera).Osservate i valori dei tre
makeVector nell'istruzione: il 1 rappresenta la posizione della telecamera ossia che noi ci troviamo
nel punto di coordinate (0,0,-30), il 2 che noi vogliamo guardare nel punto di coordinate (0,0,0)
mentre il terzo inposta come siamo girati rispetto al modo ( il punto (0,1,0) indica che noi usiamo il
sistema descritto nel disegno in alto.
Ora lo schermo inpostato per disegnare un oggetto 3D. La routine termina contiene tutto il
necessario per chiudere il programma mentre per quella muoviObj ci arriviamo subito. Qui c' il
codice del Form che fa partire il programma all'avvio' lo fa chiudere con un doppioclick e fa
muovere il cubo con le frecce direzionali e i tasti pag.
Dim cubo(35) As D3DVERTEX
Dim zoom As Single 'grandezza del cubo
Dim posizioneX As Single 'posizione del cubo
Dim posizioneY As Single 'posizione del cubo
Private Sub Form_DblClick()
termina True
End Sub
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyPageUp
zoom = zoom * 2
Case vbKeyPageDown
zoom = zoom / 2
Case vbKeyLeft
posizioneX = posizioneX - 0.5
Case vbKeyRight
posizioneX = posizioneX + 0.5
Case vbKeyDown
posizioneY = posizioneY - 0.5

Case vbKeyUp
posizioneY = posizioneY + 0.5
End Select
End Sub

Private Sub Form_Load()


'creiamo lo schermo principale
CreaSchermo 800, 600, Form1.hWnd
'facciamo riapparire lo schermo se si dovesse essere ridotto a icona
Form1.Show
creaCubo
Call mainLoop
End Sub

Sub mainLoop()
Dim angoloX As Long
zoom = 1 'imposto la grandezza del cubo a 1
1
'faccio ruotare il cubo sull'asse y e se l'angolo supera i 360 allora lo reinposto a 0
angoloX = angoloX + 1
If angoloX > 359 Then angoloX = 0
device.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, D3DColorRGBA(0, 0, 0, 0),
1#, 0 'pulisce lo schermo
device.BeginScene 'inizia il rendering
'tutto il codice che deve eseguire le varie fasi di rendering
muoviObj zoom, zoom, zoom, 15, angoloX, 0, posizioneX, 0, posizioneY
device.DrawPrimitiveUP D3DPT_TRIANGLELIST, 12, cubo(0), Len(cubo(0))
device.EndScene 'fa terminare il rendering
device.Present ByVal 0, ByVal 0, 0, ByVal 0 'invia l'immagine al monitor
DoEvents
GoTo 1
End Sub
Sub creaCubo()
'lati
'1
cubo(0) = CreaD3Dv(-1, -1, -1, 0, 0, 0, 0, 0)
cubo(1) = CreaD3Dv(-1, 1, -1, 0, 0, 0, 0, 0)
cubo(2) = CreaD3Dv(1, 1, -1, 0, 0, 0, 0, 0)
cubo(3) = CreaD3Dv(1, 1, -1, 0, 0, 0, 0, 0)
cubo(4) = CreaD3Dv(1, -1, -1, 0, 0, 0, 0, 0)

cubo(5) = CreaD3Dv(-1, -1, -1, 0, 0, 0, 0, 0)


'2
cubo(6) = CreaD3Dv(-1, -1, 1, 0, 0, 0, 0, 0)
cubo(7) = CreaD3Dv(1, -1, 1, 0, 0, 0, 0, 0)
cubo(8) = CreaD3Dv(1, 1, 1, 0, 0, 0, 0, 0)
cubo(9) = CreaD3Dv(1, 1, 1, 0, 0, 0, 0, 0)
cubo(10) = CreaD3Dv(-1, 1, 1, 0, 0, 0, 0, 0)
cubo(11) = CreaD3Dv(-1, -1, 1, 0, 0, 0, 0, 0)
'3
cubo(12) = CreaD3Dv(-1, -1, -1, 0, 0, 0, 0, 0)
cubo(13) = CreaD3Dv(1, -1, -1, 0, 0, 0, 0, 0)
cubo(14) = CreaD3Dv(1, -1, 1, 0, 0, 0, 0, 0)
cubo(15) = CreaD3Dv(1, -1, 1, 0, 0, 0, 0, 0)
cubo(16) = CreaD3Dv(-1, -1, 1, 0, 0, 0, 0, 0)
cubo(17) = CreaD3Dv(-1, -1, -1, 0, 0, 0, 0, 0)
'4
cubo(18) = CreaD3Dv(1, -1, -1, 0, 0, 0, 0, 0)
cubo(19) = CreaD3Dv(1, 1, -1, 0, 0, 0, 0, 0)
cubo(20) = CreaD3Dv(1, 1, 1, 0, 0, 0, 0, 0)
cubo(21) = CreaD3Dv(1, 1, 1, 0, 0, 0, 0, 0)
cubo(22) = CreaD3Dv(1, -1, 1, 0, 0, 0, 0, 0)
cubo(23) = CreaD3Dv(1, -1, -1, 0, 0, 0, 0, 0)
'5
cubo(24) = CreaD3Dv(1, 1, -1, 0, 0, 0, 0, 0)
cubo(25) = CreaD3Dv(-1, 1, -1, 0, 0, 0, 0, 0)
cubo(26) = CreaD3Dv(-1, 1, 1, 0, 0, 0, 0, 0)
cubo(27) = CreaD3Dv(-1, 1, 1, 0, 0, 0, 0, 0)
cubo(28) = CreaD3Dv(1, 1, 1, 0, 0, 0, 0, 0)
cubo(29) = CreaD3Dv(1, 1, -1, 0, 0, 0, 0, 0)
'6
cubo(30) = CreaD3Dv(-1, 1, -1, 0, 0, 0, 0, 0)
cubo(31) = CreaD3Dv(-1, -1, -1, 0, 0, 0, 0, 0)
cubo(32) = CreaD3Dv(-1, -1, 1, 0, 0, 0, 0, 0)
cubo(33) = CreaD3Dv(-1, -1, 1, 0, 0, 0, 0, 0)
cubo(34) = CreaD3Dv(-1, 1, 1, 0, 0, 0, 0, 0)
cubo(35) = CreaD3Dv(-1, 1, -1, 0, 0, 0, 0, 0)
End Sub
Nel form load viene chiamata l'istruzione creaSchermo inpostando la risoluzione a 800*600 mentre
con la funzione creaCubo definita in fondo al modulo si memorizza nell'array di vertici la posizione
dei punti che lo compongono. All'evento doppio click richiamo la routine termina dandogli il valore
true che fa chiudere il programma. La routine mainLoop fa eseguire tutto il lavoro di rendering
(disegno) del cubo.
All'interno del device.beginScene e device.endScene metto l'istruzione per il disegno del cubo
muoviObj zoom, zoom, zoom, 15, angoloX, 0, posizioneX, 0, posizioneY
device.DrawPrimitiveUP D3DPT_TRIANGLELIST, 12, cubo(0), Len(cubo(0))
L'istruzione device.DrawPrimitiveUp disegna il contenuto dei vertici. Gli argomenti sono

D3DPT_TRIANGLELIST che imposta il tipo di visualizzazione dei triangoli (spiegati in figura), 12


il numero dei triangoli da disegnare, cubo(0) il primo vertice dell'array mentre len(cubo(0))
diciamo la lunghezza di memoria del primo vertice (basta dare len( il primo vertice dell'array).
MuoviObj una funzione che ho creato nel mdx8 per muovere, ruotare e dimensionare facilmente e
velocemente gli oggetti.Per muovere un oggetto bisognerebbe dare a device.SetTransform
D3DTS_WORLD una matrice creata dalla moltiplicazione di queste cinque matrici dove T sono le
traslazioni, 0 sono gli angoli e S la scala.

Ci sono funzioni che aiutano in questi conti ma sono noiose e soprattutto lente per la memoria. La
funzione che ho creato (muoviObj) chiede tutti i valori per modificare la scala, la rotazione e la
traslazione di tutti gli assi. Questa risulta essere 2.5 volte pi veloce dei metodi di Dx. Se volete
capire come funziona leggetela attentamente.
Vertici
POINTLIST

LINELIST

LINESTRIP

TRIANGLELIST

TRIANGLESTRIP

TRIANGLEFAN

(prese dalle SDK di DirectX8)


Avviate il programma e vedrete il cubo ruotare sull'asse Y. Potete modificarne la posizione con le
frecce direzionali mentre con pag su e gi ne modificherete la scala. Per comprendere bene il
programma scaricatelo e leggetelo bene e soprattutto fate esperimenti sui valori e provate a
scriverne uno simile.Nella prossima lezione parleremo di luci e texture.
Cosa sono le texture? Per i pochi che non lo sapessero sono , per farla breve, delle immagini che
vengono avvolte attorno ad un oggetto 3D. Le texture sono fondamentali per rappresentare un
oggetto 3D. Immaginate di disegnare un serpente 3D : ebbene baster una piccola bitmap
raffigurante la sua pelle squamata per applicarla su di esso e ottenere cos l'effetto voluto. Inoltre per
una moltitudine di oggetti si possono risparmiare poligoni su poligoni : potrete infatti attaccare il
disegno di una faccia su un pupazzo che pi economico di dover creare un viso completamente in
3D!. Avete capito la lezione numero 3? Se si allora qui facile. Innanzitutto una texture
memorizzata in un oggetto Direct3DTexture8 che memorizza l'immagine e le caratteristiche della
texture. Esiste per una caratteristica fondamentale per le texture : la trasparenza. Infatti si pu
scegliere un colore della texture che non sar disegnato lasciando cos vuota l'immagine. Qui sotto
riportata la funzione da aggiungere al modulo mdx8 per poter creare una texture.

Function creaTex(filesrc As String, ColorKey As Long, Optional coloreK As Boolean = False) As


Direct3DTexture8
If coloreK Then
Set creaTex = D3DX.CreateTextureFromFileEx(device, filesrc, D3DX_DEFAULT, D3DX_DEFAULT,
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_POINT,
D3DX_FILTER_POINT, ColorKey, ByVal 0, ByVal 0)
Else
Set creaTex = D3DX.CreateTextureFromFile(device, filesrc)
End If
End Function
In questa funzione ho inserito due modi per creare la funzione (scusate se vi si leggono su pi righe
ma la riga di codice lunga). Nel caso in cui si imposti il colore trasparente (coloreK) su false verr
creata una texture senza colore trasparente. Con la stringa filesrc si passa semplicemente il percorso
in cui si trova il file.
Set creaTex = D3DX.CreateTextureFromFile(device, filesrc)
serve per creare una texture semplice senza colore trasparente. "Device" serve solo a dire alla
texture dove memorizzato il device. Nel caso coloreK sia inpostato su true il colore memorizzato
in ColorKey sar trasparente e la riga D3DX.CreateTextureFromFileEx.......... molto lunga. La
definizione visualizzata presa direttamente dalla documentazione il linea in inglese di DirectX8 e
vale per tutte le necessit. Se volete fare esperimenti vi dicoci che potete cambiare
:D3DX_DEFAULT, D3DX_DEFAULT sono la larghezza e l'altezza (se volete inserire dei valori
precisi inseriteli qui altrimenti lasciando le costanti verranno lasciate le dimensioni originali);
D3DX_FILTER_POINT il tipo di filtro usato (usate il completamento automatico di VB per
vedere le altre costanti stando attenti che alcune non sono supportate da molte schede video ma ci
non d problemi in genere). Nel Form del progetto dichiarate 2 variabili come Direct3DTexture8
Dim texture1 As Direct3DTexture8
Dim texture2 As Direct3DTexture8
Ora da una stessa immagine (niente risate se l'immagine buffa IO NON SO DISEGNARE )
creeremo due texture diverse: una con colore trasparente e l'altra no.
Set texture1 = creaTex(App.Path & "\face.bmp", D3DColorMake(1, 1, 1, 1), True)
Set texture2 = creaTex(App.Path & "\face.bmp", 0, False)
Bisogna usare D3DColorMake per dare il colore (il colore stavolta va da 0 a 1)
Ora la parte pi complessa. Le texture non si applicano automaticamente sugli oggetti, i vertici
vanno settati per le texture : ricordate i valori TV e TU della funzione creaD3DV ebbene bisogna
inpostare quelli.Osservate la figura

per visualizzare una texture corerttamante su un quadrato dovrete impostare le coordinate TU e TV


come in figura. Ora su un quadrato facile ma su un triangolo sar cos

Su un oggetto 3D non facile far andare d'accordo tutti i vertici per questo gi su un cubo si fa
fatica a trovare le coordinate corrette figuriamoci su sfere o addirittura sul serpente ipotizzato
all'inizio. Tuttavia non c' problema perch non bisogner disegnarci sempre cos gli oggetti : nella
prossima lezione vi spiegher come creare disegni 3D da usare in visual basic con programmi tipo
3D Studio MAX o Lightwave. Per questo esempio ho creato come oggetto 3D un quadrato e ho
inpostato i valori cos:
Sub creaquadrato()
quadrato(0) = CreaD3Dv(-1, -1, 0, 0, 0, 0, 0, 1)
quadrato(1) = CreaD3Dv(-1, 1, 0, 0, 0, 0, 0, 0)
quadrato(2) = CreaD3Dv(1, 1, 0, 0, 0, 0, 1, 0)
quadrato(3) = CreaD3Dv(1, 1, 0, 0, 0, 0, 1, 0)
quadrato(4) = CreaD3Dv(1, -1, 0, 0, 0, 0, 1, 1)
quadrato(5) = CreaD3Dv(-1, -1, 0, 0, 0, 0, 0, 1)
End Sub
Ps se impostate le TU e TV con 2 anzich con 1 l'immagine sar disegnata 2 volte sul poligono.
Fate esperimenti con il programma.
Ora nel mainLoop noterete che ho inserito due volte le istruzioni di disegno proprio per disegnare
due quadrati ognuno con una texture diversa. Ora il lavoro finito : se volete che il prossimo
poligono sia disegnato con texture inserite prima del device.DrawPrimitiveUp questa istruzione
device.SetTexture 0, texture1
Questa serve a dire che al livello 0 bisogna inserire la texture memorizzata in texture1. Attenzione

se non si modifica questa istruzione tutti i prossimi poligoni saranno disegnati con quella texture.
Per cambiare texture riusate la stessa istruzione cambiando il nome della variabile mentre se volete
che il prossimo poligono sia senza texture usate device.SetTexture 0, nothing.
Notate che ho sempre usato 0 ma possibile sovrapporre pi texture sul poligono con effetti
spettacolari. Ma questo pi complicato e riguarder un tutorial avanzato. Per ora scaricatevi
questo demo da me creato e studiatevelo.
Questo l'ultimo argomento fondamentale che bisogna sapere sul Direct3D e come ho scritto
sull'indice ora dovreste imparare un p di 2D dato che nei prossimi argomenti sar costretto a usare
alcuni di questi componenti. Argomento di questa lezione uno dei miei preferiti: le luci e l'effetto
che hanno sugli oggetti. Come avrete notato dal tutorial precedente nell'uso degli oggetti in formato
X ho usato una variabili che volontariamente non ho voluto spiegare: la D3DMaterial8. Cos'? Se
guardate all'ambiente notate che la luce non si riflette allo stesso modo su tutti gli oggetti. Ad
esempio un'auto rossa riflette appunto il rosso ai nostri occhi ma in alcuni punti in cui la luce del
sole va a riflettersi potete vedere dei riflessi bianchi. Le caratteristiche di luminosit e riflessione
sono descritti proprio da questa variabile. Una variabile definita come d3dmaterial deve essere
passata al device prima di ogni operazione del disegno tramite l'istruzione
device.setMaterial "nome della variabile"
Nel loop che disegna notate che l'ho gi inserita dato che la variabile D3DMaterial fa parte del tipo
oggX definito da me(ricordate che un array). La struttura della variabile D3DMaterial composta
da 5 sotto variabili e inoltre le prime 4 hanno anche delle sotto variabili (r,b,g,a) che sono i quattro
valori dei colori che vanno settati da 0 a 1.
Dim materiale As D3DMATERIAL8
materiale.Ambient.r = 1
materiale.diffuse.r = 1
materiale.specular.r = 1
materiale.emissive.r = 1
materiale.power = 255
Nelle prime 4 assegnazioni ho impostato al massimo il valore rosso delle varie caratteristiche
dell'oggetto (per gli oggetti caricati da file X molte sono gi settate dal vostro editor ).
Ambient indica la capacit di riflettere la luce ambientale ossia quella proveniente da tutte le
direzioni (come quelle luci diffuse di stazioni e aereoporti).
Diffuse indica la capacit di riflettere la luce che gli viene puntata addosso da fonti di luci ( la
principale e fondamentale)
Specular indica la capacit di riflettere le fonti di luce (esempio dell'auto). Un'altro esempio la
luce che si riflette sul monitor dalla finestra. ATTENZIONE E' LA LUCE NON L'IMMAGINE: IN
DIRECTX CON LA LUCE NON SI RIFLETTONO GLI OGGETTI.
Emissive indica la capacit di un oggetto di emettere luce (come un oggetto radioattivo).
Power non come le precedenti ma va impostata con un valore numerico da 0 a 255 e indica la
capacit riflessiva riferita a specular. In un prossimo tutorial spiegher un effetto molto bello da
realizzare con questa propriet.
Sui materiali ho finito; ricordatevi di impostare ogni oggetto con il suo materiale perch non come

per le texture che si pu usare Nothing per eliminarle. OGNI OGGETTO IL SUO MATERIALE.
Luci
La variabile che imposta la luce la D3dLight8 che composta da moltissime sottovariabili. Per
poter usare le luci dovrete attivare la luce nel Device,dichiarare una variabile di tipo D3dLight8,
aggiungerla al device e accenderla.Potrete aggiungere molte luci al vostro ambiente a secondo della
scheda video video ma al massimo 8 e accenderle, spegnerle, spostarle e farci tutto ci che volete.
Per attivare la luce nel device inserite questa linea.
device.SetRenderState D3DRS_LIGHTING, 1
Poi dichiarate la variabile
Dim luce As D3DLIGHT8
Impostatela (andate ai tipi per vedere come)
Aggiungetela al device
device.SetLight 0, luce
(Nota. 0 indica che la luce inserita nello slot 0; per inserire pi luci ripetete l'operazione con
un'altro indice (non obbligatoriamente consecutivo)
Infine accendete la luce
device.LightEnable 0, 1
(anche qui 0 l'indice della luce)
Esistono 3 tipi di luce in DirectX. Nell'esempio che lascio con questo tutorial vedrete il classico
Cubo illuminato da questi 3 tipi di luce. Premete 1,2 e 3 per cambiare il tipo di luce e il suo colore.
Point Light
Il primo tipo di luce (tasto 1) la luce puntiforme ossia generata da un punto nello spazio. Questo
tipo di luce quello usato ad esempio per le torce dei castelli. In base ai settaggi si potra regolarne
ad esempio il colore da riflettere, la posizione e la massima distanza a cui sar visibile. Nel mio
esempio ho inpostato la luce sul rosso e la distanza a cui visibile esattamente alla distanza del
cubo. In questo modo quando i vertici si allontanano si oscureranno. Questo tipo di luce il
secondo per il consumo di potenza.

Come settare questo tipo di luce.


luce.Type = D3DLIGHT_POINT
luce.Position.z = -10
luce.Range = 10
luce.diffuse.r = 1
device.SetLight 0, luce
Type serve per specificare il tipo di luce. Position (divisa in X,Y,Z) indica la posizione della
sorgente. Range indica la distanza. Trovate inoltre le variabili presenti in D3DMaterial che indicano
i valori della luce. Inoltre potete usare anche le sottovariabili attenuation1,2 e 3 che indicano come
la luce diminuisce con la distanza. Non usandolo semplicemente si non si vede se la distanza supera
il range.
Directional Light
La luce direzionale un tipo di luce che viene generata da un punto infinitamente lontano ma che
non si affievolisce mai. L'esempio pi classico il sole che illumina tutto ci che si trova nella sua
direzione. Per questa luce si pu impostare solo il colore e la direzione ma quella pi leggera per
prestazioni.

luce.diffuse.g = 1
luce.Type = D3DLIGHT_DIRECTIONAL
luce.Direction.z = 30
device.SetLight 0, luce
Per la direzionale non si usa la posizione ma la Direction(divisa in X,Y,Z). Per trovare la giusta
direzione si sottrae il punto che si vuole illuminare - l'origine. In questo caso z=30= 0 (punto dove si
guarda) - (-30) (origine). La luce segue questo segmento.
Spot Light
L'ultimo tipo la luce di tipo spot. Per farla breve la luce proiettata da una torcia elettrica o da un
faro. E' la pi complessa e penso che un disegno chiarisca tutto molto meglio.

Nella zona al centro la luce molto pi intensa e l'angolo delle luci descritto in radianti dai due
angoli phi e theta. Per questa luce va settata la posizione di partenza e la direzione. E' la luce a mio

avviso pi spettacolare ma anche la pi pesante per il computer. Usare troppe di queste luci
appesantiscono il programma. ATTENZIONE QUESTA LUCE CREA UN FASCIO DI LUCE MA
QUESTO NON SI VEDE FINCHE' NON URTA QUALCOSA.
luce.diffuse.b = 1
luce.Type = D3DLIGHT_SPOT
luce.Position.z = -10
luce.Direction.z = 30
luce.Range = 1000
luce.Attenuation1 = 0.001
luce.Falloff = 5
luce.Phi = 60 * rad1
luce.Theta = 30 * rad1
device.SetLight 0, luce
Qui attenuatio importante. Pi piccolo il valore e meno si attenua. Phi e Theta sono gli angoli
(NB Theta
Qui trovate l'esempio. Per le luci fate milioni di esperimenti perch capire bene il meccanismo delle
variabili dificile e spesso gli oggetti non si vedranno perch semplicemente non saranno
illuminati. Ultimo appunto:
Ambient Light
Per usarla con o senza altre luci scrive questa riga
device.SetRenderState D3DRS_AMBIENT, D3DColorMake(1, 1, 1, 1)
Attenzione per gli utenti 3D Studio: quando regolate il materiale per gli oggetti non s perch ma la
luce ambientale non impostata. Per vedere l'oggetto dovrete impostare voi la variabile ambient del
materiale (consiglio di porre Ambient=Diffuse
cubo.mateX(aus).Ambient = cubo.mateX(aus).diffuse
Ultima nota
Alpha
Cosa diavolo il valore di colore "A" accanto a R,B,G. Il valore di colore alpha un quarto valore
di colore per gli oggetti che ne indica la trasparenza. Per il momento ignoratelo, come lo girate cos
sta bene!. Per gli esempi sull' AlphaBlending sar utile oltre per poter erndere semitrasparenti gli
oggetti della grafica 2D.
Fra poco pubblicher il tutorial Luci special sulle luci degli oggetti metallici. Nella sezione speciali
di Direct3D.
Prima di passare all'argomento sulle luci passiamo ad un altro degli argomenti fondamentali: il
formato X. Cos come ogni programma 3D ha il suo formato anche Direct3D ha il suo formato che
sostituisce gli array di vertici e non solo: anche le texture e le impostazioni sulla luce degli oggetti
vengono memorizzate e questo permette di disegnare con molte meno istruzioni un ambiente 3D
anche di milioni di poligoni (anche se ci vuole un PC spaventoso per realizzare un gioco che
visualizzi milioni di poligoni quindi rimaneta tra i 3000 e i 100000 che meglio). Il formato X per
potreste farmi notare che non molto supportato (non s nemmeno se l'ultimo 3D studio lo
supporta) ma in realt questo non un problema perch la microsoft distribuisce in forma gratuita
un programma che converte il formato 3DS (il pi comune tra tutti) in formato X. La variabile che
memorizza il tutto l'oggetto D3DXMesh. Dato per che questa memorizza solo la disposizione

delle texture dobbiamo accostargli una variabile Direct3DTexture8 e una variabile D3DMaterial per
le inpostazioni luminose. Inoltre per oggetti complessi la mesh formata da pi oggetti che vanno
cos disegnati in serie. Cos ho creato un tipo che memorizza tutte le cose di un oggetto 3D anche il
pi complesso il tipo da me chiamato oggX
Type oggX
numX As Long
meshX As D3DXMesh
mateX() As D3DMATERIAL8
texX() As Direct3DTexture8
End Type
MateX() e TexX() sono due array dinamici che vengono ingranditi quando necessario.
Il programma creato visualizzer un cubo creato in 3DS avente come texture il mio logo.

Nel modulo mdx8 inserisco una nuova funzione.


'crea l'oggetto.X
Function creaMesh(filesrc As String, Optional texture As Boolean = False, Optional materiali As Boolean =
False, Optional directory As String) As oggX
'crea mesh
Dim MtrlBuffer As D3DXBuffer
Set creaMesh.meshX = D3DX.LoadMeshFromX(filesrc, D3DXMESH_MANAGED, device, Nothing,
MtrlBuffer, creaMesh.numX)
ReDim creaMesh.mateX(creaMesh.numX)
ReDim creaMesh.texX(creaMesh.numX)
Dim strTexName As String
For I = 0 To creaMesh.numX - 1
If materiali Then
' copia il materiale

D3DX.BufferGetMaterial MtrlBuffer, I, creaMesh.mateX(I)


' setta il colore dell'ambiente
End If
' Crea le texture
If texture Then
strTexName = D3DX.BufferGetTextureName(MtrlBuffer, I)
If strTexName <> "" Then
Set creaMesh.texX(I) = D3DX.CreateTextureFromFile(device, directory + "\" + strTexName)
End If
End If
Next
Set MtrlBuffer = Nothing
End Function
Questa funzione un p complessa assegna ad una variabile dichiarata come oggX tutti le
impostazioni per rappresentare un oggetto 3D. Filesrc indica il percorso dove si trova il file x, i due
booleani chiedono se si vogliono usare texture e materiali (inpostateli sempre come true che
meglio), mentre in directory va il percorso della cartella che contiene tutti i file delle texture
(IMPORTANTE per usare gli oggetti creati in 3DS dovete inserire in una cartella tutti i file
immagine usati come texture). Per il funzionamento di questa funzione si pu riassumere che
loadMeshFromX carica nella mesh i dati dell'oggetto 3D e allo stesso tempo carica altri dati nel
mtrlBuffer. Da questa otteniamo la lista dei materiali e i nomi dei file immagine delle texture che
vengono inserite in array dimensionati secondo il numero degli oggetti 3D del file. In numX verr
memorizzato tale numero. Nel nostro esempio c' solo un cubo ma se l'oggetto formato da pi
forme o addirittura vogliamo rappresentare pi oggetti nello stesso file allora sapere quanti sono
importante per la rappresentazione.
Con l'istruzione
cubo = creaMesh(App.Path & "\cubo.x", True, True, App.Path)
Creiamo il cubo dal file.
Ora al posto del drawPrimitiveUp usiamo un ciclo che disegna tutte le parti di oggX
For aus = 0 To cubo.numX - 1
device.SetTexture 0, cubo.texX(aus)
device.SetMaterial cubo.mateX(aus)
cubo.meshX.DrawSubset aus
Next aus
Con questo ciclo cubo.DrawSubset aus disegna l'oggetto numero Aus ma prima setta la texture e il
materiale (argomento della prossima lezione). Per altri chiarimenti leggete l'esempio e fate alcune
prove.

Potrebbero piacerti anche