článek

Vytvoř si svou bludišťovku – 4

Vytvoř si svou bludišťovku – 4

V dnešním díle se blíže podíváme na možnosti třídy ID3DXMesh. Jednou z jejích nejsilnějších stránek je bezesporu schopnost načítat modely ze souboru ve formátu *.X. Do tohoto formátu můžete vyexportovat svůj výtvor z mnoha modelovacích programů. Tak pojďme na věc.

Dnes nebudeme skutečně otálet a pustíme rovnou do práce. Ze všeho nejdříve si musíme vytvořit novou mesh.





LPD3DXMESH meshMaze = 0;




Již minule jsem se zmínil, že se každá mesh skládá ze subsetů. Nadeklarujeme si tedy globální proměnnou, do které poté uložíme počet subsetů naší meshe.





DWORD numSubsets;




Většina modelů má také nějakou texturu (nebo textury), což je klasický dvourozměrný obrázek, kterým je model potažen. D3D naštěstí disponuje třídou IDirect3DTexture9, která práci s texturami velmi zjednodušuje. Vytvoříme si tedy ukazatel na tuto třídu.





LPDIRECT3DTEXTURE9* texture = 0;




Velmi důležitou úlohu ve hrách hraje také osvětlení a my musíme nastavit, jak bude mesh (vlastně její jednotlivé subsety) na světlo reagovat. K tomu složí takzvané materiály, které se dají nastavit už v modelovacím programu a v D3D jednoduše načíst. O materiálech bude ještě podrobná řeč, ale my si je načteme už teď společně s texturami.





D3DMATERIAL9* material = 0;




Podívejme se nyní, jak je potřeba pozměnit funkci initMeshes(). Pro načtení modelu ze souboru použijeme funkci D3DXLoadMeshFromX. Podívejme se na ní blíže.





HRESULT D3DXLoadMeshFromX (
LPCTSTR pFilename,
DWORD Options,
LPDIRECT3DDEVICE9 pD3DDevice,
LPD3DXBUFFER * ppAdjacency,
LPD3DXBUFFER * ppMaterials,
LPD3DXBUFFER * ppEffectInstances,
DWORD * pNumMaterials,
LPD3DXMESH * ppMesh
);








  • pFilename – Řetězec, kterým určíme, kde se soubor nachází

  • Options – Použijeme D3DXMESH_MANAGED, takže mesh bude ve videopaměti

  • pD3DDevice – Ukazatel na d3ddev

  • ppAdjacency – Nebudeme potřebovat

  • ppMaterials – Buffer, který obsahuje popis materiálů a cest k texturám

  • ppEffectInstances – Nebudeme potřebovat

  • pNumMaterials – Počet subsetů meshe

  • ppMesh – Naplní maší mesh potřebnými daty






V praxi to potom vypadá následovně. Vytvoříme si buffer pro uložení informací o materiálech a texturách.





LPD3DXBUFFER bufMaterial;




A načteme mesh.





D3DXLoadMeshFromX("bludiste.x", D3DXMESH_MANAGED, d3ddev, NULL, &bufMaterial, NULL, &numSubsets, &meshMaze);




Vytvoříme strukturu D3DXMATERIAL, abychom z bufferu vydolovali data.





D3DXMATERIAL* tempMaterials = (D3DXMATERIAL*)bufMaterial->GetBufferPointer();




Nastal čas vytvořit si konečně materiály a textury. Vytvoříme si tedy jejich pole podle počtu subsetů.





material = new D3DMATERIAL9[numSubsets];
texture = new LPDIRECT3DTEXTURE9[numSubsets];




Pomocí for cyklu jednoduše naplníme naše materiály a textury daty. Počítáme s tím, že ne kažný subset musí mít texturu.





for(DWORD i = 0; i < numSubsets; i++)
{
material[i] = tempMaterials[i].MatD3D;
if(FAILED(D3DXCreateTextureFromFile(d3ddev,
tempMaterials[i].pTextureFilename,
&texture[i]))) texture[i] = 0;
}







Uvolníme buffer.





bufMaterial->Release();




Takhle vypadá universální kód, pro načtení jakéhokoliv modelu s libovolným počtem subsetů a textur.


Předtím, než mesh vykreslíme nám zbývá probrat jednu věc jménem zbuffer. A k čemu takový zbuffer slouží. V reálném světě překrývají z vašeho pohledu objekty, které jsou k vám blíže ty, které jsou dál. Například můžete palcem překrýt slunce. Stejného chování se snažíme docílit i v naší hře. Bez použití zbufferu by byl každý objekt překryt jiným objektem, který byl vykreslen poněm a jsou z hlediska pohledu alespoň částečně za sebou.


Vytvoříme si tedy objekt IDirect3DSurface9, který bude náš zbuffer reprezentovat.





LPDIRECT3DSURFACE9 zbuffer = 0;




Do funkce initD3D přidáme funkci po vytvoření zbufferu. Pro naše potřeby stačí znát první dva parametry, kam udáme rozlišení okna a ke konci ukazatel na náš zbuffer.





d3ddev->CreateDepthStencilSurface(screenWidth, screenHeight, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, TRUE, &zbuffer, NULL);




Tuto novinu musíme sdělit i D3D pomocí struktury d3dpp. Zapneme používání zbufferu a nastavíme jeho pixel-format na 16 bitů.





d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;




Pomocí funkce SetRenderState zapneme zbuffer.





d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);




Tolik ve stručnosti o této problematice.


Nyní však konečně přistoupíme k vykreslování. Na začátek funkce Render nám přibyla funkce pro vymazání zbufferu.





d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0,0), 1.0f, 0);




Vymažme vykreslování předešlé meshe s konvicí, protože využijeme její Word matrix, a začneme vykreslovat bludiště. Využijeme k tomu for cykl, který bude trvat podle počtu subsetu. V každém cyklu nastavíme danému subsetu materiál (momentálně k ničemu), texturu a nakonec vykreslíme samotný subset. Podmínkou si ještě zjistíme, zdali existuje pro daný subset textura.





for(DWORD i = 0; i < numSubsets; i++)
{
d3ddev->SetMaterial(&material[i]);
if(texture[i] != 0) d3ddev->SetTexture(0, texture[i]);
meshMaze->DrawSubset(i);
}







Mesh a textury musíme při ukončení aplikace uvolnit ve funkci relaeaseD3D.





if(meshMaze!=0) meshMaze->Release();
for(unsigned int i=0; i {
if(texture[i] != 0) texture[i]->Release();
}







Nastavíme word a view matrix, jak nám vyhovuje a pokud bychom nyní projekt spustili, bludiště by se nám sice zobrazilo, ale bylo by úplně černé, jako předešlá konvice a navíc by se zdálo, že půlka stěn chybí.








Vše se dá lehce napravit. Vraťme se zpět do funkce initD3D. Za černé stěny může fakt, že máme zapnuté osvětlení, ale ve scéně žádná světla. Vypneme ho tedy.





d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);










A proč nejsou vidět některé stěny. Může za to fakt, že jsou dané facy (kdyby někdo nevěděl, facy jsou trojúhelníky, ze kterých se skládá každý model) vykreslovány pouze z jedné strany. Tato praktika se běžně používá kvůli navýšení výkonu. V tomto případě ale poněkud kazí dojem, takže jí vypneme.





d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);










A bludiště je na světě. Zbývá nám jen poslední kosmetická úprava. Jistě nejsem jediný, komu se v této fázi nezamlouvá vzhled textur. K tomu použijeme filtry. Vysvětlování, jak fungují by zabralo hodně času a pro nás to není úplně nezbytné, takže těm zvídavým doporučím tradičně dokumentaci DirectX.





d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
d3ddev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);










Tato konfigurace zaručí slušný vzhled při nízkých hardwarových nárocích.



Dnešní dílo je dokonáno. Příště se budeme zabývat uživatelským vstupem a vytvářením FPS kamery.



Kompletní zdrojové kódy (všechny díly seriálu): bludistovka_zdroje.zip



Související odkazy:






pavlík_petr

autor
/ pavlík_petr

Publikováno: 02.12.2007


další články této kategorie





diskuze

odeslat

Nejsi automat? Napiš výsledek 2 + 2 =

Drticka

Drticka | 30.05.18 v 10:46

mám hruzu z blludiště

Tiv | 17.12.07 v 15:26

Konečně nějaký serial o programování her v Direct3D/c++. Děkuji autorovi za články. Jen tak dál!