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.

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:

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 291x (49.22 kB)
Aplikace je včetně zdrojových kódů v jazyce C#