1. díl - XNA tvorba ve 3D - dva je více než jeden

C# .NET XNA game studio 3D grafika 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

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

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.


 

Stáhnout

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

 

  Aktivity (1)

Článek pro vás napsal vodacek
Avatar
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.

Jak se ti líbí článek?
Celkem (2 hlasů) :
55555


 


Miniatura
Všechny články v sekci
Základy 3D grafiky a tvorba enginu
Miniatura
Následující článek
XNA tvorba ve 3D - textury

 

 

Komentáře

Avatar
David Jančík [sczdavos]:

Ááááh pecička. Odevzdávám bojový úkol a těším se na pokračování :P Jsem natěšenej, až si vykreslím nějaké jednoduché 3D těleso :)

Odpovědět  +1 4.12.2012 16:21
Čím více času dostaneš, tím méně ho máš.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na David Jančík [sczdavos]
David Čápka:

Jsem rád, že to bereš takhle od začátků :) Předpokládám, že přiště bude těleso? Docela se na to těším.

Odpovědět 4.12.2012 20:23
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
vodacek
Redaktor
Avatar
vodacek:

nebude

 
Odpovědět  +1 4.12.2012 20:36
Avatar
pardal486
Člen
Avatar
pardal486:

Zdravím. Mám takový záhadný problém. Dělal jsem vše podle tutoriálů dokonce jsem zkopíroval celý stažený zdrojový kód, ale prostě nefunguje. Když spustím stažený projekt kompilace proběhne úplně bez problémů. Když ovšem vytvořím nový projekt, zkopíruji celý kód a zkompiluji tak se mi zobrazí chyba. Zkoušel jsem i další projekt ale prostě nefunguje.

Odpovědět 30.12.2012 2:20
Bite my shiny, metal ass!
Avatar
pardal486
Člen
Avatar
pardal486:

Omlouvám se. Problém byl vyřešen. Stačilo dat. typ int nahradit shortem. Ale pořád mi nejde do hlavy že v tom staženém to jede úplně v pohodě.

Odpovědět 30.12.2012 2:41
Bite my shiny, metal ass!
Avatar
vodacek
Redaktor
Avatar
Odpovídá na pardal486
vodacek:

jdi do nastavení projektu a tam v záložce s XNA přepni z Reach na Hi-Def a znovu to zkus zkompilovat, pokad máš grafickou kartu kompatibilní tak by to mělo jít

 
Odpovědět 30.12.2012 8:37
Avatar
pardal486
Člen
Avatar
Odpovědět 30.12.2012 13:29
Bite my shiny, metal ass!
Avatar
regaktivo
Člen
Avatar
regaktivo:

Mam taketo body:

Vertices[ 0 ] = new VertexPositionColor( new Vector3( -100f, 0f, 0f ), Color.Green );
Vertices[ 1 ] = new VertexPositionColor( new Vector3( -100f, -40f, 0f ), Color.Blue );
Vertices[ 2 ] = new VertexPositionColor( new Vector3( 0f, -40f, 0f ), Color.White );
Vertices[ 3 ] = new VertexPositionColor( new Vector3( 0f, 0f, 0f ), Color.Red );

Taketo indexy:

Indices[ 0 ] = 0;
Indices[ 1 ] = 1;
Indices[ 2 ] = 2;
Indices[ 3 ] = 3;

A takto to vyhraslujem:

GD.DrawUserIndexedPrimitives<VertexPositionColor>( PrimitiveType.TriangleStrip, Vertices, 0, Vertices.Length, Indices, 0, 3 );

Vykresluje to tak srandovne - z jednej strany zobrazi trojuholnik a ked to otocim o 180 stupnov (zo zadnej strany), tak zobrazi obdlznik.
V com mam chybu ?

Editováno 13.8.2013 15:55
 
Odpovědět 13.8.2013 15:53
Avatar
vodacek
Redaktor
Avatar
vodacek:
GD.DrawUserIndexedPrimitives<VertexPositionColor>( PrimitiveType.TriangleStrip, Vertices, 0, Vertices.Length, Indices, 0, 3 );

co tam dělá ta trojka?

 
Odpovědět 14.8.2013 12:31
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.