Lekce 10 - XNA tvorba ve 3D - Model podruhé
Vítejte po jedenácté. V minulé lekci, XNA tvorba ve 3D - Kamera, jsme se věnovali kameře.
V tomto díle si znovu nasázíme model, tentokráte do našeho enginu. Můžete si to ostatně zkusit také sami, nebude tam nic neznámého, vše už bylo vysvětleno v předchozích dílech.
Model
Model se naše třída jmenovat nebude, důvod je snad jasný, už jednu
třídu Model
z XNA
známe. Nazveme si ji tedy
Model3D
, nebo jakkoliv libovolně podle vašeho uvážení. Opět
bude umístěna ve složce s komponentami, opět učiníme třídu veřejnou a
upravíme jmenný prostor a třída bude opět dědit od komponenty. Nečekaně.
Vytvoříme si proměnnou, kde budeme uchovávat jméno souboru s modelem a
samotný model:
private string modelName; protected Model Model;
Potřeba bude proměnná pro určení pozice našeho modelu ve světě, jeho natočení a jeho měřítka:
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; } }
Rotace je ukládána jako matice schválně. Je to asi nejvíce uživatelsky přívětivé, jak uvidíte později. Vytvoříme si také konstruktor, vlastně několik přetížených konstruktorů. Budou se hodit všechny:
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; }
Pokud by se vám to ale nechtělo všechno psát, tak stačí pouze jeden, ale opět je to jen a jenom na vás. Přepíšeme metodu `Load a v ní model nahrajeme:
protected override void Load(){ Model = Parent.Engine.Content.Load<Model>(modelName); }
Potřeba bude také uložit si do pole transformace předávané z modelovacího programu. Už jsme to dělali předtím, takže si vytvoříme toto pole:
private Matrix[] transformace;
A v metodě Load
pole naplníme:
transformace=new Matrix[Model.Bones.Count];
Model.CopyAbsoluteBoneTransformsTo(transformace);
Opět bez komentáře, protože jsme to dělali již jednou, zbývá nám
pouze vykreslování. Takže přepíšeme metodu Draw
a model
vykreslíme. Použijeme tu metodu, kterou jsme si připravili v minulém
díle:
public override void Draw(Matrix View, Matrix Projection, Vector3 CameraPosition){ }
Vytvoříme si matici World
pro náš model:
Matrix world = Utility.CreateWorld(Pozice, Rotace, Meritko);
Ještě by bylo dobré poznamenat, že jsem si přesunul třídu
Utility
, kterou jsme si připravili v minulých dílech do projektu
s enginem. To jen dodávám pro pořádek. Model si vykreslíme stejně, jak
jsme to dělali posledně:
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 jsme hotoví. Máme vše připraveno, aby bylo možné model vykreslit. Možná se vám zdá, že to je příliš moc práce pro takovéto snadné věci. Je to pravda. Ale jak půjdeme stále hlouběji a hlouběji a nebudeme potřebovat jeden model, ale třeba dvacet, tak se nám investovaná práce a úsilí velmi rychle vrátí. Vytvořený kód hned použijeme. Zkusíme si náš koberec přidat do našeho herního okna. Otevřeme si soubor, kde máme uloženo naše herní okno. Zakomentujeme všechny komponenty až na barevné pozadí. Přidáme si kameru:
Kamera = new TargetKamera(this, new Vector3(100, 150, 0), Vector3.Zero);
Kamera je na pozici (100,150,0)
a dívá se na bod
(0,0,0)
, stejně jako v pátém díle, kdy jsme si model přidali
poprvé. Nyní přidáme komponentu s naším modelem. Opět použijeme koberec
jako v díle pátém
AddComponent(new Model3D(new Vector3(0, 0, 0), "koberec1"));
Hotovo. Projet si zkompilujeme a spustíme a uvidíme následující výsledek:

Model je úspěšně přidán v enginu. Zde by klidně mohl být konec tohoto
dílu, ale to bych nesměl být já, kdybych neměl něco v rukávu. Něco na co
jsem úmyslně opomněl, když jsme vytvářeli komponentu Sprite
.
SpriteBatch
totiž při použití nenavrací stav grafické karty
do původního stavu. Musíme jej navrátit ručně. Pokud si nyní navrátíme
do našeho herního okna vykreslení spritu, tak uvidíme jak zmizely černé
okraje kolem koberce. Ne, že by to nebylo žádoucí, ale není to dobře.
Musíme při vykreslení čehokoliv, kde je používána
SpriteBatch
, uklidit vše do původního stavu. Není to nic
záludného stačí na to tři řádky:
Parent.Engine.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
Parent.Engine.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
Parent.Engine.GraphicsDevice.BlendState = BlendState.Opaque;
Prvním nastavíme správný mod pro texturování, druhý nám opět zapne depth buffer a poslední vypne používání alfa kanálu a průhlednosti jako takové. Tyto stavy grafické karty si určitě zaslouží více povídání, ale prozatím mi budete muset věřit, že to dělá to co dělá a že toto chceme, aby to tak bylo. Více o nich prozradím až se budeme věnovat shaderům. Pokud nyní hru spustíte, tak je již vše tak jak má být. Stejné tři řádky přidáme i k textovému popisku.
A to je pro dnešek vše.
Příště, XNA tvorba ve 3D - vykreslení trojúhelníku, si napíšeme rozhraní pro klávesnici a myš, je to poslední důležitá věc, kterou je potřeba udělat, aby engine byl použitelný pro něco praktičtějšího a více použitelného. Čekám také na komentáře pod článkem, kterým se nějak nechce. Zatím tedy na shledanou a snad se uvidíme příště.
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 224x (1.7 MB)
Aplikace je včetně zdrojových kódů v jazyce C#