10. diel - XNA tvorba v 3D - Model druhýkrát
Vitajte po jedenástej. V tomto diele si znovu zasadíte nejaký ovocný model, tentokrát do nášho enginu. Môžete si to napokon skúsiť tiež sami, nebude tam nič neznámeho, všetko už bolo vysvetlené v predchádzajúcich dieloch.
Model
Model sa naša trieda menovať nebude, dôvod je snáď jasný, už jednu
triedu Model
z XNA
poznáme. Nazveme si ju teda
Model3D
, alebo akokoľvek ľubovoľne podľa vášho uváženia.
Opäť bude umiestnená v zložke s komponentmi, opäť urobíme triedu verejnú
a upravíme menný priestor a trieda bude opäť dediť od komponenty.
Nečakane. Vytvoríme si premennú, kde budeme uchovávať meno súboru s
modelom a samotný model:
private string modelName; protected Model Model;
Potreba bude premenná pre určenie pozície nášho modelu vo svete, jeho natočenie a jeho mierky:
private Vector3 fPozice; private Matrix fRotace; private Vector3 fMeritko; public Vector3 Pozice{ get{ return fPozice; } set{ fPozice = value; } } public Matrix Rotace{ get{ return fRotace; } set{ fRotace = value; } } public Vector3 Meritko{ get{ return fMeritko; } set{ fMeritko = value; } }
Rotácia je ukladaná ako matice schválne. Je to asi najviac užívateľsky prívetivé, ako uvidíte neskôr. Vytvoríme si tiež konštruktor, vlastne niekoľko preťažených konstruktoru. Budú sa hodiť všetky:
public Model3D(Vector3 pozice, string model): this(pozice,Matrix.Identity,model){ } public Model3D(Vector3 pozice, Matrix rotace, string model): this(pozice,rotace,Vector3.One,model){ } public Model3D(Vector3 pozice, Matrix rotace, Vector3 meritko, string model){ Pozice = pozice; modelName = model; Meritko = meritko; Rotace = rotace; }
Ak by sa vám to ale nechcelo všetko písať, tak stačí iba jeden, ale opäť je to len a len na vás. Prepíšeme metódu `Load a v nej model nahráme:
protected override void Load(){ Model = Parent.Engine.Content.Load<Model>(modelName); }
Potreba bude tiež uložiť si do poľa transformácie odovzdávané z modelovacieho programu. Už sme to robili predtým, takže si vytvoríme toto pole:
private Matrix[] transformace;
A v metóde Load
poľa naplníme:
transformace=new Matrix[Model.Bones.Count];
Model.CopyAbsoluteBoneTransformsTo(transformace);
Opäť bez komentára, pretože sme to robili už raz, zostáva nám len
vykresľovanie. Takže prepíšeme metódu Draw
a model
vykreslíme. Použijeme tú metódu, ktorú sme si pripravili v minulom
diele:
public override void Draw(Matrix View, Matrix Projection, Vector3 CameraPosition){ }
Vytvoríme si maticu World
pre náš model:
Matrix world = Utility.CreateWorld(Pozice, Rotace, Meritko);
Ešte by bolo dobré poznamenať, že som si presunul triedu
Utility
, ktorú sme si pripravili v minulých dieloch do projektu s
enginom. To len dodávam pre poriadok. Model si vykreslíme rovnako, ako sme to
robili posledne:
foreach (ModelMesh mesh in Model.Meshes){ foreach (ModelMeshPart part in mesh.MeshParts){ if (part.Effect is BasicEffect){ BasicEffect efekt = part.Effect as BasicEffect; efekt.View = View; efekt.Projection = Projection; efekt.World = transformace[mesh.ParentBone.Index] * world; efekt.EnableDefaultLighting(); } } mesh.Draw(); }
A sme hotoví. Máme všetko pripravené, aby bolo možné model vykresliť. Možno sa vám zdá, že to je príliš veľa práce pre takéto ľahké veci. Je to pravda. Ale ako pôjdeme stále hlbšie a hlbšie a nebudeme potrebovať jeden model, ale treba dvadsať, tak sa nám investovaná práce a úsilia veľmi rýchlo vráti. Vytvorený kód hneď použijeme. Skúsime si náš koberec pridať do nášho herného okna. Otvoríme si súbor, kde máme uložené naše herné okno. Zakomentujeme všetky komponenty až na farebné pozadie. Pridáme si kameru:
Kamera = new TargetKamera(this, new Vector3(100, 150, 0), Vector3.Zero);
Kamera je na pozícii (100,150,0)
a pozerá sa na bod
(0,0,0)
, rovnako ako v piatom diele, kedy sme si model pridali
prvýkrát. Teraz pridáme komponent s naším modelom. Opäť použijeme
koberec ako v diele piatom
AddComponent(new Model3D(new Vector3(0, 0, 0), "koberec1"));
Hotovo. Prejsť si skompilujeme a spustíme a uvidíme nasledujúce výsledok:
Model je úspešne pridaný v engine. Tu by pokojne mohol byť koniec tohto
dielu, ale to by som nesmel byť ja, keby som nemal niečo v rukáve. Niečo na
čo som úmyselne opomenul, keď sme vytvárali komponent Sprite
.
SpriteBatch
totiž pri použití nenavracia stav grafickej karty do
pôvodného stavu. Musíme ho navrátiť ručne. Ak si teraz vrátime do nášho
herného okna vykreslenie Spritu, tak uvidíme ako zmizli čierne okraje okolo
koberca. Nie, že by to nebolo žiaduce, ale nie je to dobre. Musíme pri
vykreslenie čohokoľvek, kde je používaná SpriteBatch
, upratať
všetko do pôvodného stavu. Nie je to nič záludného stačí na to tri
riadky:
Parent.Engine.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
Parent.Engine.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
Parent.Engine.GraphicsDevice.BlendState = BlendState.Opaque;
Prvým nastavíme správny mod pre textúrovanie, druhý nám opäť zapne depth buffer a posledný vypne používanie alfa kanálu a transparentnosti ako také. Tieto stavy grafickej karty si určite zaslúži viac rozprávanie, ale zatiaľ mi budete musieť veriť, že to robí to čo robí a že toto chceme, aby to tak bolo. Viac o nich prezradím až sa budeme venovať shaderům. Ak teraz hru spustíte, tak je už všetko tak ako má byť. Rovnaké tri riadky pridáme ik textovému popisku.
A to je pre dnešok všetko. Nabudúce si napíšeme rozhranie pre klávesnicu a myš, je to posledná dôležitá vec, ktorú je potrebné urobiť, aby engine bol použiteľný pre niečo praktickejšieho a viac použiteľného. Čakám tiež na komentáre pod článkom, ktorým sa nejako nechce. Zatiaľ teda dovidenia a snáď sa uvidíme nabudúce.
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é 224x (1.7 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#