Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 1 - XNA tvorba ve 3D - dva je více než jeden

Vítejte v druhé části seriálu o 3D v XNA. Minule jsme si v 3D prostoru vykreslili trojúhelník. V tomto díle se podíváme hlouběji pod pokličku toho jak vykreslovat trojúhelníky. Nejprve se podíváme více na enum PrimitiveType a jaké v sobě skrývá možnosti. Posléze na možnosti naší vlastní uživatelsky definované indexace (tady jsi nejsem jist pojmenováním, ale pro naše účely tomu tak můžeme říkat) vrcholů.

PrimitiveType je enum, který jsme používali minule přímo jako parametr při volání metody, která se postarala o vykreslení našeho trojúhelníku. Pro připomenutí vypadala takto:

GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, vert, 0, 1);

Enum nám udává jakým způsobem mají být jednotlivé vertexy pospojovány ať již do trojúhelníků a nebo do čar. Nabývá v poslední verzi XNA (to jest verze 4) pouze čtyřech hodnot. Dvě z nich slouží pro vykreslování čar (LineList a LineStrip) a další dvě pro vykreslení trojúhelníku (TriangleList a TriangleStrip).

  • LineList spojuje vertexy čárami a to vždy tak, že vezme jeden jako počáteční bod a druhý jako bod koncový.
  • LineStrip naproti předešlé hodnotě vezme první bod jako počáteční a pak tvoří jakéhosi pomyslného hada až k poslednímu bodu
  • TriangleList je obdoba LineListu, jen se vytvářejí trojúhelníky a to po trojicích.
  • TriangleStrip je opět obdoba LineStripu ale s tím rozdílem, že se utvoří první trojúhelník a vezme se další bod a znovu se vytvoří další, nejlépe je to snad vidět na obrázku dole.
TriangleStrip - Základy 3D grafiky a tvorba enginu

Postup udaný enumem se opakuje tolikrát, kolik je zadáno v posledním parametru volání naší metody. V našem případě máme jeden trojúhelník. Jak jsem již minule upozorňoval často se může vyskytnout chyba právě v tomto parametru. Často je k vidění výjimka ArgumentOutOfRangeException. Jak se jí vyvarovat? Obvykle stačí dobře si napočítat počty vykreslovaných útvarů a také si ohlídat zda-li na to máme dostatek nadefinovaných vertexů. To druhé lze snadno spočítat, kolik jich bude potřeba při zvolené té a nebo oné metody. Počty jsem shrnul v následující tabulce. Pod písmenkem n si dosaďte počet vykreslovaných objektů.

Typ Počet
LineList 2*n
LineStrip n+1
TriangleList 3*n
TriangleStrip n+2

Je jasně vidět, která z metod je úspornější, ale ne vždy ji/je lze použít. Příkladem budiž třebas taková krychle. Pokud bychom chtěli každou stěnu stejně barevnou, pak ano, můžeme vzít pouze 4 vertexy a ty mezi sebou pospojovat do tvaru krychle. Pokud bychom ale potřebovali, aby každá stěna byla jinak barevná, musíme sáhnout po 24 vertexech. Je to relativní a vždy je potřeba zvolit to, co je pro danou situaci vhodné.

Může se ovšem také stát, že ani jedna z nabízených metod nám nevyhovuje a potřebujeme si udat vlastní pravidla hry. K tomu slouží právě ona indexace, u které si nejsem jist, jak se správně jmenuje, ale nevadí, budeme tomu tak pro naše potřeby říkat. Není to nic tak strašného, jedná se jen a pouze o obyčejné pole intů, respektive datového typu short. Osobně používám inty. V poli jednoduše definujeme indexy v poli vertexů, které se mají spolu spojit. Opět ale musíme udat metodu, jak se mají výsledné útvary vykreslovat. Nejlepší bude ukázat si to na příkladu. Ještě jsme si oficiálně nevykreslili žádné čáry a pro jednoduchost a demonstraci použití jsou čáry ideální. Budeme tedy chtít vykreslit třebas křížek. Samozřejmě že to lze udělat snadněji s použitím pouze dvou čar, ale to nyní nechme stranou :-) Kdybychom chtěli vše vyřešit bez indexování, tak při použití LineListu bychom potřebovali 8 vertexů (podle tabulky výše n=4 a tak 2*4 by mohlo být 8 ), LineStrip dokonce vůbec nepřichází v úvahu. Za použití indexování se můžeme dostat na pěkných 5 vertexů. Jeden ve středu a další 4 jako konce. Založíme si 2 proměnné jedna je naše známé pole pro vertexy a druhé je pole pro indexy:

VertexPositionColor[] krizekVert;
int[] krizekIdx;

Následně si je v metodě Intialize nastavíme na námi požadované hodnoty:

krizekVert=new VertexPositionColor[5];
krizekVert[0] = new VertexPositionColor(new Vector3(-30,0,0),Color.Orange);//stred
krizekVert[1] = new VertexPositionColor(new Vector3(-40,0,0), Color.Green);
krizekVert[2] = new VertexPositionColor(new Vector3(-30,10,0), Color.Green);
krizekVert[3] = new VertexPositionColor(new Vector3(-20,0,0), Color.Green);
krizekVert[4] = new VertexPositionColor(new Vector3(-30,-10,0), Color.Green);

krizekIdx = new int[] {
    0,1,
    0,2,
    0,3,
    0,4
};

Jako střed jsme zvolili vertex na pozici 0 a ostatní jsou jen napozicovány kolem něj. V poli s indexy pak již jen definujeme, že se každý další má spojit čárou s nultým. Poslední věcí která zbývá je vykreslení. To se odehraje v metodě Draw a zařídíme jej následujícím řádkem:

GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.LineList, krizekVert, 0, krizekVert.Length, krizekIdx, 0, 4);

Opět je použita generická metoda jako posledně, ovšem nyní je to metoda jiná. Posledně to byla DrawUserPrimitives, takže rozhodně to není stejná metoda. Prvním parametr nám zůstal od minula, v našem případě máme indexy nadefinované jako seznam čar, takže LineList je jasná volba. Dalším parametrem je opět pole s vertexy, nula opět zůstává jako offset. A nyní je již všechno nové. Dalším parametrem je počet vertexů, asi když bychom měli delší pole a nechtěli jej použít celé, tak můžeme takto počet uvažovaných vertexů omezit. Osobně tam vždy cpu délku pole. Další parametr je naše pole s indexy, další opět offset ale tentokráte v poli s indexy. Poslední hodnota udává opět počet vykreslených objektů, tedy v našem případě 4 čáry. Ještě než si program spustíme, mírně posuneme kameru, aby se nám vše do výsledku pěkně vešlo:

effect.View = Matrix.CreateLookAt(new Vector3(0, 0, 30), new Vector3(0,0,0), Vector3.Up);

Nyní je kamera v bodě (0,0,30) a dívá se přímo na bod (0,0,0). Vše je připraveno můžeme spouštět. Výsledek by měl, pokud jste provedli vše správně a já v to doufám, vypadat nějak jako na tomto obrázku:

Výsledek - Základy 3D grafiky a tvorba enginu

To by zas mohlo pro dnešek i stačit. Dnes do pomyslného slovníčku nic nepřidáme, ale nevěste hlavy ještě toho bude hodně :-) A jako takový bojový úkol si můžete zkusit z čar vykreslit třeba hvězdičku.

V příští lekci, XNA tvorba ve 3D - textury, se budeme věnovat texturám.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 288x (49.22 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

Všechny články v sekci
Základy 3D grafiky a tvorba enginu
Přeskočit článek
(nedoporučujeme)
XNA tvorba ve 3D - textury
Článek pro vás napsal vodacek
Avatar
Uživatelské hodnocení:
3 hlasů
Vodáček dělá že umí C#, naplno se již pět let angažuje v projektu ŽvB. Nyní studuje na FEI Upa informatiku, ikdyž si připadá spíš na ekonomice. Není mu také cizí PHP a SQL. Naopak cizí mu je Java a Python.
Aktivity