4. díl - XNA tvorba ve 3D - Modely

C# .NET XNA game studio 3D grafika XNA tvorba ve 3D - Modely

Vítejte popáté, minule jsme probrali souřadnice a matice 3D světa. V tomto díle se podíváme na vykreslování modelu. Ano, již konečně model. Vedou mě k tomu neodkladné skutečnosti posunout se od snadných objektů, na kterých se sice vše dobře vysvětluje a názorně ukazuje, ale model je přece model.

Model je v XNA reprezentován třídou Model. Jak by se dalo čekat. Model není nic jiného, než soustava trojúhelníků. Jsou to ty jedny a samé trojúhelníky, se kterými jsme si v předchozích dílech hráli. XNA dovede nahrát modely ve formátu .x, což je jakýsi DirectX formát, ale já spíše doporučuji formát fbx. Do něj dovedou exportovat všechny běžně používané modelovací programy. (i z sketch-upu se nám to povedlo!) Jenom pozor, musí být export do fbx verze 2010. Doporučuji také ukládat v ASCII režimu a ne v binárním, jak se ostatně přesvědčíte nížeji. Často je potřeba do modelu šáhnout a upravit adresy pro textury na relativní. Zajímavý, leč anglický článek o možných úskalích exportu z oblíbeného 3dsmaxu naleznete zde, děkuji zmijozelákovi za poskytnutí. Pro naše zkoušení jsem namátkově vybral jeden z modelů z projektu ŽvB2. Je to perský kobereček. Naleznete jej dole v archivu. Do projektu jej dostaneme stejně jako texturu. Projekt jsem opět vyčistil, aby se nám tam naše předešlé výtvory nepletly. Vytvoříme si proměnnou pro model:

Model model;

V metodě LoadContent model nahrajeme:

model = Content.Load<Model>("koberec1");

Nyní zkusíme projekt zkompilovat. Vše bez problémů. Že ne? No jistěže ne, jinak bych to přeci po vás nechtěl. Dostali jsme tuto chybu:

Missing asset "C:\Documents and Settings\Prokop\Dokumenty\PVR\Textury\koberec1_uvw mapa_3.png"

Nemůže se najít textura našeho koberce. Ano, to je pochopitelné, ne na všech počítačích se jmenuje účet Prokop a ne na všech počítačích budeme mít texturu v této složce. Zde právě přichází na řadu to, proč je dobré mít model v ASCII formátu. Pokud by soubor byl uložen binárně, tak se samozřejmě nic neděje. Lze jej překonvertovat třeba tímto nástrojem přímo od Autodesku. Opět pozor na verzi, ta musí být opět 2010. Lze jej snadno otevřít v libovolném textovém editoru (myšlen ne Word) a mírně upravit k obrazu našemu. V souboru pak stačí najít místa, kde se všude nachází Prokop nebo případně PRV nebo jiná význačná část ze stávající adresy souboru. Většinu adresy umažeme a necháme pouze:

koberec1_uvw mapa_3.png

Změnu je u tohoto souboru nutné provést celkem na čtyřech řádcích (1848,1849,18­74,1875). Tuto činnost lze určitě automatizovat třeba nějakým plug-inem do Visual Studia. Pokud by měl někdo zájem pomoci a třeba u toho rovnou napsat, jak se mu povedlo ten plug-in udělat, má zde příležitost. Dále musíme soubor s texturou nahrát do složky Content. Texturu také naleznete v archivu, ale tentokráte již na svém místě ve složce Content. Nemusíme ji vkládat přes Visual Studio, protože je na něj odkaz má náš model a XNA si jej vyzvedne samo. Pokud nyní projekt zkompilujeme, vše se již povede bez chyb a my můžeme pokračovat dále. Vytvoříme si pole typu Matrix, kde budeme skladovat transformace dané přímo modelovacím programem.

Matrix[] transforms;

Ano slyšíte dobře, transformace, není to nic jiného než matice World, která je ovšem v tomto případě daná přímo z modelovacího programu. Jedná se opět o natočení modelu, změnu měřítka a podobně, ale tentokrát ne od nás, ale od modelovacího programu. Přesuneme se do metody LoadContent, kde právě vytvořené pole inicializujeme a naplníme hodnotami:

transforms=new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);

Dále si připravíme objekt pro samotné vykreslení. Stejně jako u trojúhelníku i zde musíme nastavit parametry efektu (shaderu, zvykejte si i na tento pojem) a to konkrétně všechny tři matice. Jenomže model není tak snadná záležitost jako jeden trojúhelník. Jistě, skládá se z nich také, ale jeho struktura je složitější. XNA rozlišuje takzvané meshe, reprezentováno třídou ModelMesh. Pod tímto pojmem si lze představit jeden souvislý povrch modelu. Třeba hlavu postavy. Dále každý/á mesh má své části. Zde nazvané meshpart, a to ve třídě ModelMeshPart. Povětšinou má každá mesh pouze jednu část. Záleží ale na její komplikovanosti. Právě tyto části v sobě obsahují již připravené efekty, které čekají na nastavení hodnot. Nastavíme tedy všude hodnoty matic View, Projection a World a povolíme jakési základní osvětlení:

foreach (ModelMesh mesh in model.Meshes){
  foreach (ModelMeshPart part in mesh.MeshParts){
    BasicEffect ef = part.Effect as BasicEffect;
    ef.View = Matrix.CreateLookAt(new Vector3(100, 150, 0), new Vector3(0, 0, 0), Vector3.Up);
    ef.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDevice.DisplayMode.AspectRatio, 1, 1000);
    ef.World = transforms[mesh.ParentBone.Index];
    ef.EnableDefaultLighting();
  }
}

Jistě, není to optimální řešení. Matice lze vypočítat i mimo cyklus a pak jen nastavovat. Povšimněte si nastavení matice World. Zde používáme hodnoty z připraveného pole. Nyní se přemístíme do metody Draw. Jak vykreslit model? Máme hned několik možností. Je ale dobré se již nyní naučit tuto, protože se nám bude v pozdějších dílech více hodit:

foreach (ModelMesh mesh in model.Meshes){
  mesh.Draw();
}

To je vše. Nic moc těžkého nebo náročného. Pokud nyní program spustíte, měli byste vidět nádherný perský koberec od Junita (tímto děkuji, že mi ten model půjčil, pamatuj na trojku!!).

koberec z pohádky o létajícím koberci jako model v XNA

Skvěle. A jelikož se toho zdá být málo tak přidáme jednoduchou animaci. Vytvoříme si proměnnou s maticí pro rotaci:

Matrix rotace;

V metodě Initialize ji nastavíme na výchozí hodnotu:

rotace = Matrix.Identity;

Matice Identity (česky jednotková) je taková matice, která má na své hlavní diagonále samé jedničky. Je to jediná matice, se kterou když vynásobíme matici jinou, tak výsledek je stejný jako předtím. V metodě Update přidáme zvětšení rotace o nějaký malý úhel. Otáčíme kolem osy Y:

rotace *= Matrix.CreateRotationY(0.01f);

Násobíme předešlou matici maticí novou, tím dosáhneme toho, že se úhly sečtou. Pak již jen v metodě Draw nastavíme nový parametr do World matice a můžeme model opět vykreslit:

foreach (ModelMesh mesh in model.Meshes){
  foreach (ModelMeshPart part in mesh.MeshParts){
    BasicEffect ef = part.Effect as BasicEffect;
    ef.World = transforms[mesh.ParentBone.Index]*rotace;
  }
  mesh.Draw();
}

Všimněte si, že násobíme matici World z editoru a maticí naší. Nikoliv obráceně. Jinak by výsledek nebyl ten, který požadujeme. Schválně si to zkuste. Násobení matic není komutativní tedy A*B není to samé jako B*A. Uvedený způsob animací není ovšem optimální. Hodně záleží na FPS, jak se z tohoto problému vymanit si ukážeme zase někdy příště.

Tak a to je pro dnešek vše. Opět se těším na reakce a komentáře, které zatím přicházejí jen když si o ně řeknu. Jako úkol si zkuste s pomocí návodů z 2D série napsat jednoduché ovládání otáčení modelu pomocí třeba šipek. Příště se podíváme na... a víte co nechte se překvapit.


 

Stáhnout

Staženo 359x (1.58 MB)
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 (3 hlasů) :
55555


 



 

 

Komentáře
Zobrazit starší komentáře (9)

Avatar
vodacek
Redaktor
Avatar
vodacek:

to je v předchozím díle, X jde ------------> tam Y jde nahorů a Z souřadnice směřuje směrem z monitoru k tobě, ale je to jen a jenom o tom jak je narafičena kamera

 
Odpovědět 30.12.2012 21:44
Avatar
anyone
Neregistrovaný
Avatar
anyone:

Budou i tutorialy na animaci objektu? Nemyslim animaci jako je tady, ale napr. u toho koberce aby se ruzne vlnil apod.

 
Odpovědět 7.1.2013 17:31
Avatar
vodacek
Redaktor
Avatar
Odpovídá na anyone
vodacek:

to možné není protože koberec je tvořen málo částmi, musel by mít více trojúhelníků ale ano lze to

 
Odpovědět 7.1.2013 17:55
Avatar
anyone
Neregistrovaný
Avatar
Odpovídá na vodacek
anyone:

To byl jen priklad. Spis me zajimalo jestli sem o tom neco napises.

 
Odpovědět 7.1.2013 17:58
Avatar
vodacek
Redaktor
Avatar
Odpovídá na anyone
vodacek:

teď se bludišťuje, animace se tam moc nehoděj třeba se na to někdy dostane

 
Odpovědět 7.1.2013 18:14
Avatar
Daniel Kosík (Ghost4Man):

Bohužel mi to v MonoGame nefunguje... "Cannot load <jmeno> asset as a non-content file" Tohle to píše u načítání modelu... Mám tam ten XNB soubor, takže by to mělo fungovat... Cestu jsem kontroloval, model jsem si odsud stáhl a ve VS s XNA jsem si nechal vygenerovat ten XNB soubor... Nemáte s tím někdo zkušenosti (v MonoGame)?

Editováno 22.8.2014 22:12
Odpovědět 22.8.2014 22:11
Všechno na světě můžete chtít. Jenom nemůžete chtít, aby se vám chtělo.
Avatar
vodacek
Redaktor
Avatar
Odpovídá na Daniel Kosík (Ghost4Man)
vodacek:

budeš muset ukázat jak to nahráváš, ten řádek

 
Odpovědět 22.8.2014 22:29
Avatar
Odpovídá na vodacek
Daniel Kosík (Ghost4Man):
model = Content.Load<Model>(@"Models\koberec1");
Odpovědět 22.8.2014 22:34
Všechno na světě můžete chtít. Jenom nemůžete chtít, aby se vám chtělo.
Avatar
vodacek
Redaktor
Avatar
Odpovídá na Daniel Kosík (Ghost4Man)
vodacek:

mělo by se používat normální lomítko /

 
Odpovědět 22.8.2014 23:22
Avatar
Odpovídá na vodacek
Daniel Kosík (Ghost4Man):

Už to funguje, ale v lomítku problém nebyl... Napřed jsem tam měl všechno na Copy if newer, potom jsem ale přehodil XNB soubor a tam jsem to zapomněl nastavit...

Editováno 24.8.2014 22:25
Odpovědět 24.8.2014 22:25
Všechno na světě můžete chtít. Jenom nemůžete chtít, aby se vám chtělo.
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 10 zpráv z 19. Zobrazit vše