Vianoce v ITnetwork sú tu! Dobí si teraz kredity a získaj až 80 % extra kreditov na e-learningové kurzy ZADARMO. Zisti viac.
Hľadáme nové posily do ITnetwork tímu. Pozri sa na voľné pozície a pridaj sa k najagilnejšej firme na trhu - Viac informácií.

1. diel - XNA tvorba v 3D - dvaja je viac ako jeden

Vitajte v druhej časti seriálu o 3D v XNA. Minule sme si v 3D priestore vykreslili trojuholník. V tomto diele sa pozrieme hlbšie pod pokrievku toho ako vykresľovať trojuholníky. Najprv sa pozrieme viac na enum PrimitiveType a aké v sebe skrýva možnosti. Neskôr na možnosti našej vlastnej užívateľsky definované indexácie (tu si nie som istý pomenovaním, ale pre naše účely tomu tak môžeme hovoriť) vrcholov.

PrimitiveType je enum, ktorý sme používali minule priamo ako parameter pri volaní metódy, ktorá sa postarala o vykreslenie nášho trojuholníka. Pre pripomenutie vyzerala takto:

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

Enum nám udáva akým spôsobom majú byť jednotlivé vertexy pospájané či už do trojuholníkov a alebo do čiar. Vstupuje v poslednej verzii XNA (to jest verzia 4) iba štyroch hodnôt. Dve z nich slúžia pre vykresľovanie čiar (LineList a LineStrip) a ďalšie dve pre vykreslenie trojuholníka (TriangleList a TriangleStrip).

  • LineList spája vertexy čiarami a to vždy tak, že vezme jeden ako počiatočný bod a druhý ako bod koncový.
  • LineStrip naproti predošlej hodnote vezme prvý bod ako počiatočný a potom tvoria akéhosi pomyselného hada až k poslednému bodu
  • TriangleList je obdoba LineListu, len sa vytvárajú trojuholníky a to po trojiciach.
  • TriangleStrip je opäť obdoba LineStripu ale s tým rozdielom, že sa utvorí prvý trojuholník a vezme sa ďalší bod a znovu sa vytvorí ďalšia, najlepšie je to snáď vidieť na obrázku dole.
TriangleStrip - Základy 3D grafiky a tvorba enginu

Postup udaný enum sa opakuje toľkokrát, koľko je zadané v poslednom parametri volanie našej metódy. V našom prípade máme jeden trojuholník. Ako som už minule upozorňoval často sa môže vyskytnúť chyba práve v tomto parametri. Často je k videniu výnimka ArgumentOutOfRangeException. Ako sa jej vyvarovať? Obvykle stačí dobre si napočítať počty vykreslovaných útvarov a tiež si ustrážiť či ak na to máme dostatok nadefinovaných vertexov. To druhé sa dá ľahko spočítať, koľko ich bude potrebné pri zvolenej tej alebo onej metódy. Počty som zhrnul v nasledujúcej tabuľke. Pod písmenkom n si dosaďte počet vykreslovaných objektov.

typ počet
LineList 2 * n
LineStrip n + 1
TriangleList 3 * n
TriangleStrip n + 2
Je jasne vidieť, ktorá z metód je úspornejší, ale nie vždy ju / je možné použiť. Príkladom nech trebárs taká kocky. Ak by sme chceli každú stenu rovnako farebnú, potom áno, môžeme vziať iba 4 vertexy a tie medzi sebou pospájať do tvaru kocky. Ak by sme ale potrebovali, aby každá stena bola inak farebná, musíme siahnuť po 24 vertex. Je to relatívna a vždy je potrebné zvoliť to, čo je pre danú situáciu vhodné.

Môže sa však tiež stať, že ani jedna z ponúkaných metód nám nevyhovuje a potrebujeme si udať vlastné pravidlá hry. K tomu slúži práve ona indexácie, u ktorej si nie som istý, ako sa správne volá, ale nevadí, budeme tomu tak pre naše potreby hovoriť. Nie je to nič také strašné, jedná sa len a len o obyčajné pole int ov, respektíve dátového typu short. Osobne používam inty. V poli jednoducho definujeme indexy v poli vertexov, ktoré sa majú spolu spojiť. Opäť ale musíme udať metódu, ako sa majú výsledné útvary vykresľovať. Najlepšie bude ukázať si to na príklade. Ešte sme si oficiálne nevykreslili žiadne čiary a pre jednoduchosť a demonštráciu použitia sú čiary ideálne. Budeme teda chcieť vykresliť trebárs krížik. Samozrejme že to možno urobiť ľahšie s použitím iba dvoch čiar, ale to teraz nechajme bokom :-) Keby sme chceli všetko vyriešiť bez indexovanie, tak pri použití LineListu by sme potrebovali 8 vertexov (podľa tabuľky vyššie n = 4 a tak 2 * 4 by mohlo byť 8), LineStrip dokonca vôbec neprichádza do úvahy. Za použitia indexovanie sa môžeme dostať na pekných 5 vertexov. Jeden v stredu a ďalšie 4 ako konca. Založíme si 2 premenné jedna je naša známe pole pre vertexy a druhé je pole pre indexy:

VertexPositionColor[] krizekVert;
int[] krizekIdx;

Následne si ich v metóde Intialize nastavíme na nami požadovanej 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
};

Ako stred sme zvolili vertex na pozícii 0 a ostatné sú len napozicovány okolo neho. V poli s indexami potom už len definujeme, že sa každý ďalší má spojiť čiarou s nultým. Poslednou vecou ktorá zostáva je vykreslenie. To sa odohrá v metóde Draw a zariadime ho nasledujúcim riadkom:

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

Opäť je použitá generická metóda ako posledne, avšak teraz je to metóda iná. Naposledy to bola DrawUserPrimitives, takže rozhodne to nie je rovnaká metóda. Prvým parameter nám zostal od minula, v našom prípade máme indexy nadefinované ako zoznam čiar, takže LineList je jasná voľba. Ďalším parametrom je opäť pole s vertexy, nula opäť zostáva ako offset. A teraz je už všetko nové. Ďalším parametrom je počet vertexov, asi keď by sme mali dlhší poľa a nechceli ho použiť celé, tak môžeme takto počet uvažovaných vertexov obmedziť. Osobne tam vždy cpu dĺžku poľa. Ďalšia parameter je naša pole s indexmi, ďalší opäť offset ale tentokrát v poli s indexy. Posledná hodnota udáva opäť počet vykreslených objektov, teda v našom prípade 4 čiary. Ešte než si program spustíme, mierne posunieme kameru, aby sa nám všetko do výsledku pekne vošlo:

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

Teraz je kamera v bode (0,0,30) a pozerá sa priamo na bod (0,0,0). Všetko je pripravené môžeme spúšťať. Výsledok by mal, ak ste vykonali všetko správne a ja v to dúfam, vyzerať nejako ako na tomto obrázku:

výsledok - Základy 3D grafiky a tvorba enginu

To by zas mohlo pre dnešok i stačiť. Dnes do pomyselného slovníčku nič nepridáme, ale nevešajte hlavy ešte toho bude veľa :-) A ako taký bojovú úlohu si môžete skúsiť z čiar vykresliť treba hviezdičku.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 291x (49.22 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Všetky články v sekcii
Základy 3D grafiky a tvorba enginu
Preskočiť článok
(neodporúčame)
XNA tvorba v 3D - textúry
Článok pre vás napísal vodacek
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
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