| Ad_Infinitum |
| Administrator |

 |
 |
| Data inscrierii: 23/Iun/2007 |
| Mesaje: 212 |
|
|
|
 |
 |
 |
|
Tutorial 2
- Introducere in Direct3D, Triunghiuri -
Download source code
E pe la 11 noaptea, asa ca imi veniti cu o bere pentru tutorialul curent. (alta decat pe cea pe care o beau acum )
In acest tutorial vom crea o fereastra D3D si vom desena un patrat texturat.
Sa incepem cu niste elemente de baza despre 3D si placa noastra grafica,
pentru care am dat atitia bani sa aiba "de toate".
Functionarea acceleratoarelor grafice sunt tare complicate,
dar ceea ce ne intereseaza pe noi, e la ce s-au gandit baietii de la firmele mari de profil,
cand au stat zi si noapte ca sa mai primeasca vreun punct in plus la testele de la reviste.
Ei au gandit astfel: obiectele 3D sa fie compuse din triunghiuri,
ele sa poata fii texturate, iar descrierea imaginii sa fie vectoriala.
De fapt placa grafica se ocupa mai mult de texturare,
si ar putea fi numit "accelerator 2D" iar restul il face DirectX-ul.
(placile moderne au si cateceva imbunatatiri cum ar fi "Hardware transform & Lighting",
dar nu exista inca un "pure" device, care sa poate functiona fara grija transformariolor efectuate de CPU)
Cum functioneaza: se specifica coordinate in spatiu (x, y, z) numite "vertice" ("vertex" e plural pt. "vertice",
dar cateodate mai citesti "vertices" sau "vertexes" gresite de altfel)
Pentru a crea un triughi, se vor specifica 3 coordinate.
La ifecare coordinata, se va mai aduga cate o coordinata de texturare numita "TU" respectiv "TV".
(alias "UV mapping" de la 3dsmax)
UV mapping functioneaza astfel: ai o imagine de rezolutia sa spunem 320x240.
TU este pe orizontala, iar TV pe verticala. TU si TV sunt din intervalul [0, 1]
0 insemnand primul pixel din partea stanga a imaginii, iar 1 va insemna pixelul din dreapta,
adica pixelul 320.-lea din textura noastra. (textura inseamna fotografie incarcata in memorie gata de folosit)
La fel si TV 0 e coltul de sus a imaginii, iar 1 va insemna 240.
0 <-- TU --> 1
^
|
TV
|
V
1
ex: TU = 0.5 TV = 0.5 va insemna pixelul din mijlocul imaginii
Daca vrem sa afisam o poză (textura), vom crea un dreptunghi texturat.
Pentru a crea un dreptunghi avem necesitate de 2 triunghiuri.
(0,0) |-----| (1,0)
| 1 |
| |
| |
| 2 |
(0,1) |-----| (1,1)
Obiectul va arata astfel:
XYZ TU/TV
triunghi1:
(0,0,0) (0,0)
(320,0,0) (1,0)
(320,240,0) (1,1)
triunghi2:
(0,0,0) (0,0)
(0,240,0) (1,0)
(320,240,0) (1,1)
Cam multa teorie asa deodata, dar e destul de rudimentar de fapt.
Daca alterati marimea dreptunghiului, D3D va destul de lungi textura,
este asa numitul "streching", careia se pot atribui niste filtre mai tarziu.
Dar ia sa vedem si putin cod sa fie mai clar:
frmMain
| Citat: |
Dim bRunning As Boolean
Private Sub Form_Load()
Me.Show
Direct3D.PreCheck 'Precheck the device, initialize DX objects
bRunning = Direct3D.InitD3D(False) 'Init the device,
bRunning = Direct3D.InitGeometry() 'Init Geometry
Do While bRunning
Direct3D.Render 'Render the scene
DoEvents
Loop
Direct3D.TerminateDirect3D 'Clean up device and DirectX objects
End
End Sub
Private Sub Form_Unload(Cancel As Integer)
bRunning = False
End Sub
Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyEscape Then bRunning = False 'if Escape key is pressed Quit program
End Sub
|
Direct3D.bas
| Citat: |
'''''''''''''''''''''''''''''''''''''''''
'(C) 2005 Osvath - Boros Robert '
' osvathrobi@hotmail.com '
'''''''''''''''''''''''''''''''''''''''''
'-----------------------------------------
'Here I will implement Direct3D functions
'such as Initializing, Rendering,
'Device autodetection, Device termination
'-----------------------------------------
Option Explicit
Public DX As New DirectX8 'Our main DirectX object
Public D3DX As New D3DX8 'D3DX is a helper library
Public D3D As Direct3D8 'The main Direct3D object
Public D3DDevice As Direct3DDevice8
'Theese values will be used for quick conversions between trigonometrical values
Public Const PI = 3.14159 'Peee :P
Public Const RAD = PI / 180 'Convert to RADIANS
Public Const DEG = 180 / PI 'Convert to DEGREES
'Converting Degrees to Radiants will look like: 45 * RAD will result the value: Pi / 4
'Converting Radians to Degrees will look like: Pi/4 * DEG will result the value: 45
'Don't worry conversions will not be used in this tutorial, but catch up on your Trigo. skills ;)
Public Declare Function GetTickCount Lib "kernel32" () As Long 'Substitute timer object
Dim Dispmode As D3DDISPLAYMODE 'Stores the DisplayResolution, and other information
Dim D3DWindow As D3DPRESENT_PARAMETERS 'Our Direct3D window
Dim DevCaps As D3DCAPS8 'Our Graphics Hardware capabilities
Dim DevIdent As D3DADAPTER_IDENTIFIER8 'The name of our Hardware (graphics card)
Private Type TL_VERTEX
X As Single
Y As Single
Z As Single
rhw As Single
color As Long
TX As Single
TY As Single
End Type
Public Const FVF_TL_VERTEX = (D3DFVF_XYZRHW Or D3DFVF_DIFFUSE Or D3DFVF_TEX1)
Public myObject(0 To 3) As TL_VERTEX
Dim Texture As Direct3DTexture8
Public Function InitD3D(FullSCR As Boolean) As Boolean
'--------------------------------------------------------------'
'Checks device caps. If available, then initializes them. '
'If every initialization was succesfull, true is being returned'
'--------------------------------------------------------------'
On Error GoTo BailOutInit
'On Error Resume Next ' Use this if you want to force the program to start
'> Presentation Parameters
If FullSCR Then
D3DWindow.Windowed = 0
D3DWindow.BackBufferFormat = Dispmode.Format
D3DWindow.BackBufferCount = 1
D3DWindow.BackBufferWidth = Dispmode.Width
D3DWindow.BackBufferHeight = Dispmode.Height
Else
D3DWindow.Windowed = 1
D3DWindow.BackBufferFormat = Dispmode.Format
End If
D3DWindow.hDeviceWindow = frmMain.hWnd
D3DWindow.SwapEffect = D3DSWAPEFFECT_COPY ' D3DSWAPEFFECT_COPY
'> Stencil depth
If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Dispmode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16) = D3D_OK Then
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16
D3DWindow.EnableAutoDepthStencil = 1
Else
D3DWindow.EnableAutoDepthStencil = 0
End If
'> Hardware/Software VP & initialization
Set D3DDevice = D3D.CreateDevice(0, D3DDEVTYPE_HAL, frmMain.hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, D3DWindow)
If D3DDevice Is Nothing Then Set D3DDevice = D3D.CreateDevice(0, D3DDEVTYPE_HAL, frmMain.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DWindow)
InitD3D = True
Exit Function
BailOutInit:
InitD3D = False
MsgBox "There was an error initializing the graphics engine!", vbInformation
End Function
Public Sub TerminateDirect3D()
'-----------------'
'Unloading objects'
'-----------------'
Set D3DX = Nothing
Set D3DDevice = Nothing
Set D3D = Nothing
Set DX = Nothing
'MsgBox "Ready"
End Sub
Public Function PreCheck() As Boolean
'--------------------------------------------'
'Displays information about graphics adapter,'
'and creates our main Dx Objects. '
'--------------------------------------------'
Set DX = New DirectX8
Set D3D = DX.Direct3DCreate()
Set D3DX = New D3DX8
D3D.GetDeviceCaps D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, DevCaps
D3D.GetAdapterIdentifier D3DADAPTER_DEFAULT, D3DENUM_NO_WHQL_LEVEL, DevIdent
D3D.GetAdapterDisplayMode D3DADAPTER_DEFAULT, Dispmode
Dim a As Single
frmMain.Caption = "> Graphics adapter: "
For a = 0 To 511
frmMain.Caption = frmMain.Caption & Chr(DevIdent.Description(a))
Next a
frmMain.Caption = frmMain.Caption & " / " & "> Screen Resolution: " & " / " & " " & CStr(Dispmode.Width) & "x" & CStr(Dispmode.Height)
End Function
Public Sub Render()
'------------------------------------------------------------'
'The entire rendering of objects, and presentation on screen '
'------------------------------------------------------------'
D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &H0, 1#, 0
D3DDevice.BeginScene
D3DDevice.SetTexture 0, Texture
D3DDevice.SetRenderState D3DRS_LIGHTING, 0
D3DDevice.SetVertexShader FVF_TL_VERTEX
D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 4, myObject(0), Len(myObject(0))
D3DDevice.EndScene
D3DDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
Public Function InitGeometry() As Boolean
'On Error GoTo bail
myObject(0) = CreateTLvertex(0, 0, 0, 1, &HFFFFFF, 0, 0)
myObject(1) = CreateTLvertex(320, 0, 0, 1, &HFFFFFF, 1, 0)
myObject(2) = CreateTLvertex(0, 240, 0, 1, &HFFFFFF, 0, 1)
myObject(3) = CreateTLvertex(320, 240, 0, 1, &HFFFFFF, 1, 1)
Set Texture = D3DX.CreateTextureFromFile(D3DDevice, App.Path & "tex.jpg")
InitGeometry = True
Exit Function
bail:
InitGeometry = False
End Function
Public Function CreateTLvertex(mX As Single, mY As Single, mZ As Single, mrhw, mcolor As Long, mtu As Single, mtv As Single) As TL_VERTEX
CreateTLvertex.X = mX
CreateTLvertex.Y = mY
CreateTLvertex.Z = mZ
CreateTLvertex.rhw = mrhw
CreateTLvertex.color = mcolor
CreateTLvertex.TX = mtu
CreateTLvertex.TY = mtv
End Function
|
Cum ati vazut in primul tutorial vom crea formul si modulul pentru functiile directx. (nu uitati sa dati pe la project>references pentru libraria dx for visual basic)
Prima diferenta o gasim la declararea de variabile in Direct3D.bas .
| Citat: |
Private Type TL_VERTEX
X As Single
Y As Single
Z As Single
rhw As Single
color As Long
TX As Single
TY As Single
End Type
Public Const FVF_TL_VERTEX = (D3DFVF_XYZRHW Or D3DFVF_DIFFUSE Or D3DFVF_TEX1)
Public myObject(0 To 3) As TL_VERTEX
|
In primul rand cream o structura numita (de mine) "TL_VERTEX" ("transformed and lit vertex").
Inseamna ca ii vom trimite D3DDevice-ului coordinate finale, si nu e trebuință sa le calculeze el.
Facem acest lucru ca sa fim siguri ca obiectul va fi desenat pe un loc vizibil pe monitor.
In loc de tu si tv i-am dat nume de tx si ty sa fie mai clar. RHW va preciza ca avem o coordinata finala. (va fi 1)
Color este optional, dar mai tarziu va fi important, in particular cand vom vorbi de iluminare.
Pentru fiecare structura de acest tip, se va preciza o constanta numita "Vertex shader".
Vertex shader nu are (aproape) nimic de a face cu umbre (shader is not shadow creator)
Vertex shader este de fapt informatia care ii spune Direct3D-ului cum dorim sa trimitem datele pentru device.
Structura TL_VERTEX poate sa contina si alte date in afara de cele precizate acum.
Fiind ceva flexibil, avem nevoie de o descriere pentru a preciza cum arata de fapt.
| Citat: |
Public Const FVF_TL_VERTEX = (D3DFVF_XYZRHW Or D3DFVF_DIFFUSE Or D3DFVF_TEX1)
|
De aici vine si numele: "FVF - Flexible Vertex Format"
D3DFVF_XYZRHW - inseamna coordinatele xyz urmat de rhw
D3DFVF_DIFFUSE - inseamna ca urmeaza o culoare
D3DFVF_TEX1 - inseamna ca urmeaza coordinate de textura (pe inițialul stagiu, despre stagii mai tarziu)
In final putem crea structura noastra. Vom utiliza o matrice de 4 elemente,
pentru ca D3D iti da probabilitatea sa descrii doua triunghiuri cu 4 puncte,
veti vedea la rendering imediat.
| Citat: |
Dim Texture As Direct3DTexture8
|
Aici vom stoca textura, pe care o incarcam cu susținerea unei functii din libraria D3DX, mai precis CreateTextureFromFile.
Observati ca avem o functie numita "InitGeometry". Aici vor intra toate procedurile de incarcare a obiectelor.
(De întocmai am facut o functie de utilitate numita CreateTLVertex, ca sa fie codul mai curat)
| Citat: |
myObject(0) = CreateTLvertex(0, 0, 0, 1, &HFFFFFF, 0, 0)
myObject(1) = CreateTLvertex(320, 0, 0, 1, &HFFFFFF, 1, 0)
myObject(2) = CreateTLvertex(0, 240, 0, 1, &HFFFFFF, 0, 1)
myObject(3) = CreateTLvertex(320, 240, 0, 1, &HFFFFFF, 1, 1)
|
1 |-----| 2
| / |
| / |
| / |
|/ |
3 |-----| 4
| Citat: |
Set Texture = D3DX.CreateTextureFromFile(D3DDevice, App.Path & "tex.jpg")
|
Textura se incarca usor. D3DX are f. numeroase functii de acest gen
Si in sfirsit am ajuns la functia "Render". Sa-l vedem in detaliu.
Cum ati vazut in primul tutorial, functia render incepe cu stergerea cadrului vechi.
Dupa care urmeaza "Begin Scene".
| Citat: |
D3DDevice.SetTexture 0, Texture
|
Textura pe care tocmai am creat-o in InitGeometry, este setata pe întâiul stagiul de texturi (stagiul 0).
(despre "texture stages" vom avea un tutorial amanuntit mai tarziu)
| Citat: |
D3DDevice.SetRenderState D3DRS_LIGHTING, 0
|
D3DDevice are o procedura numita "SetRenderState" care ne va fi utila,
deoarece se pot specifica detalii despre cum sa deseneze deviceul un anumit obiect.
Incercati sa tipariti manual comanda "D3ddevice.setrenderstate" si apasind tasta space,
veti primi toate constantele posibile. Una din aceste constante este "Lighting"
(D3DRS -> Direct 3D Render State) Asta inseamna ca nu dorim iluminare calculata de device
pentru obiectul care urmeaza sa fie desenat. ("0" inseamna ca obiectul va fi iluminat 100%,
"1" ar insemna calcularea iluminarii obiectului de catre Dx)
| Citat: |
D3DDevice.SetVertexShader FVF_TL_VERTEX
|
Prin metoda SetVertexShader, ii spunem Deviceului ce fel de vertexe fvf ii vom trimite.
FVF_TL_VERTEX, cum v-am mentionat mai sus este o constanta prin care descriem verticele noastre.
Iar in sfirsit:
| Citat: |
D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 4, myObject(0), Len(myObject(0))
|
Sa vedem DrawPrimitiveUp in detaliu!
DrawPrimitiveUp ( primitive type, primitive count, vertexstream zero data array, vertex stream zero stride )
Primitive type - D3DPT_LINELIST (cate 2 elemente)
- D3DPT_LINESTRIP (min. 2 element)
- D3DPT_POINTLIST (min. 1 element)
- D3DPT_TRIANGLEFAN (min. 3 elemente)
- D3DPT_TRIANGLELIST (cate 3 elemente)
- D3DPT_TRIANGLESTRIP (min. 3 elemente)
Primitive_Count - cate elemente sa citeasca din matrice.
Vertexstreamzerodataarray - numele cam complicat, de fapt e primul element din matricea noastra
vertex stream zero stride - marimea unui element din matrice. (ex.: Len(myobject(0))
Cum vedeti si pe imaginea atasata LINELIST inseamna ca deviceul urmeaza sa primeasca o lista de cate 2 vertice.
Pentru 6 elemente in matrice, insemana un primitive count de 3, pentru ca daca specifici o lista de 6 elemente,
o linie e alcatuita din cate doua, insemna ca ai specificat 3 linii.
Linestrip inseamna ca oricare punct nou, va fi legat de ultimul din matrice.
Daca ai 2 puncte, deseneaza o linie. Daca mai adaugi un puct, atunci o va conecta de ultimul punct,
si asa mai departe. Primitivecount va fi numarul punctelor.
Pointlist e f. usor: o lista de puncte. Primitive count va fi numarul punctelor.
Triangle list e o lista de triunghiuri. Primitive count va fi numarul punctelor impartit la 3.
Deviceul va desena cate un triunghi din fiecare 3 puncte.
TriangleStrip e exact ca line strip, iar fiecare punct nou, va fi conectat de ultimele 2 puncte din matrice.
Astfel vor fi 3 si va desena un triunghi.
(Tri-strip si Tri-list sunt cel mai des folosite)
Si in sfirsit TriFan: fiecare punct nou va alcatui un triunghi,
cu debutantul punct din matrice, si ultima. "Fan" vine de la "ventilator"
deoarece obiectul desenat va arata ca un fel de ventilator
Incercati sa trimiteti Deviceului on obiect făcut de voi (specificati inca cateva puncte pentru myobject),
si jucati-va cu distincte primitive type-uri. Dar aveti grija la primitive count:
daca nu mai sunt date, si deviceul le cauta, poate cauza diferite anomalii.
(de obicei reprezentate de un system restart )
Cam atat pentru astazi, spor la treaba. Urmatorul tutorial va fi mult mai interesant.
(Vom crea primul nostru cub rotitor!)
Pe curand.
-------------------------------------------
Tutorial written by: Osvath - Boros Robert
Petru reclamatii, sugestii sau altele scrieti-mi: osvathrobi@hotmail.com
PS: (explicatia greseliilor de exprimare: gandesc in lb. maghiara, documentatia dx e in engleza, iar eu scriu romaneste ) |
|