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.
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 |
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ť , 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:
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#