NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.

Lekce 4 - XNA tvorba ve 3D - Modely

Vítejte popáté, minule, XNA tvorba ve 3D - souřadnice a matice 3D světa, 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 - Základy 3D grafiky a tvorba enginu

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.

V následující lekci, XNA tvorba ve 3D - Engine poprvé, si napíšeme základ našeho vlastního herního 3D enginu.


 

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

 

Předchozí článek
XNA tvorba ve 3D - souřadnice a matice 3D světa
Všechny články v sekci
Základy 3D grafiky a tvorba enginu
Přeskočit článek
(nedoporučujeme)
XNA tvorba ve 3D - Engine poprvé
Článek pro vás napsal vodacek
Avatar
Uživatelské hodnocení:
3 hlasů
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