Lekce 9 - XNA tvorba ve 3D - Kamera
Vítejte podesáté. V minulé lekci, XNA tvorba ve 3D - Sprity a Text, jsme si představili Sprity a Text.
Dnes se opět vydáme do prostoru se třemi rozměry. Prozatím jsme si
vytvořili jen komponenty vykreslované přes SpriteBatch
, proto
aby bylo možné ono jedno D přidat bude potřeba trochu více než jen to.
Budeme potřebovat kameru, kde si uložíme naše známé matice (konkrétně
View
a Projection
) a další potřebné věci. Je to
hodně práce tak se do toho pustíme, ať to máme hotovo.
Kamera
Jak už jsem naznačil v úvodu, budeme v kameře ukládat nám známé dvě matice a také polohu kamery. Námi vytvořená základní kamera bude poměrně hloupá. Dokonce bude abstraktní, takže z ní nepůjde vytvořit instance. Zároveň ale bude obsahovat vše společné pro další kamery, které už budou použitelné. V původním enginu od Seana jsou kamery komponenty a zároveň jsou uloženy v nějakém service kontaineru. Zdá se mi to moc složité a proto se opět vydávám cestou jednoduchosti. Kameru si uložíme do proměnné v herním okně. Ale to až za chvíli, předně si ji musíme vytvořit. Přidáme si tedy novou složku kamery, nebo si ji ostatně pojmenujte jak uznáte za vhodné. Do ní přidáme soubor s třídou Kamera. Upravíme stejně jako tradičně jmenný prostor a také učiníme třídu veřejnou a abstraktní. Pro kolegu sokola raději rekapitulaci:
public abstract class Kamera{ }
Potřebovat budeme určitě obě matice View
a
Projection
, tak si je do třídy připravíme:
private Matrix fView; private Matrix fProjection; public Matrix View{ get{ return fView; } set{ fView = value; } } public Matrix Projection{ get{ return fProjection; } set{ fProjection = value; } }
Společná pro všechny budoucí kamery bude také jejich pozice v prostoru. Vytvořme si tedy na to také proměnnou:
private Vector3 fPozice; public Vector3 Pozice{ get{ return fPozice; } set{ fPozice = value; } }
Dále se bude hodit určení toho jak daleko kamera vidí, tedy definice
far plain
. Pokud si vzpomínáte na obrázek kamery, tak je to
právě zadní plocha, vše co se nalézá za ní nebude vykresleno.
Near plain
si zakládat nebudeme, protože bude vždy 1. Ať vás
nikoho nenapadne dávat tam jinou hodnotu.
private float fFarPlane; public float FarPlane{ get { return fFarPlane; } set{ fFarPlane = value; } }
Vytvoříme si také konstruktor a v něm nastavíme far plane
na 1000
. Tato hodnota ale záleží na konkrétním použití.
Není ale dobré volit ji příliš velikou. Jako parametr předáme herní
okno, ke kterému kamera patří, a uložíme si jej:
protected GameScreen Parent; public Kamera(GameScreen okno){ Parent = okno; FarPlane = 1000f; }
Potřeba bude také virtuální metoda Update
, skrze kterou
budeme měnit pozici kamery a v ní přepočítávat matice pro
vykreslování:
public virtual void Update(){ }
Jednu matici není potřeba počítat stále dokola, protože se nemění.
Matice View
to není, pohled se mění, ale matice
Projection
je stále stejná. Můžeme si ji vytvořit v
konstruktoru:
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, Parent.Engine.GraphicsDevice.Viewport.AspectRatio, 1f, FarPlane);
Metoda je stále stejná jako jsme ji používali dříve, takže ji
přejdeme bez komentáře. Ještě by bylo vhodné matici znovu vygenerovat
když změníme FarPlane
, přidáme tedy stejný řádek i do
setteru této proměnné:
set{ fFarPlane = value; Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, Parent.Engine.GraphicsDevice.Viewport.AspectRatio, 1f, fFarPlane); }
Z této třídy je to vše, více obecného a společného pro všechny
kamery asi nenalezneme, pokud ano, tak si to sem přidáme. Přemístíme náš
zájem do třídy GameScreen
, kde si přidáme proměnnou na
kameru:
public Kamera Kamera{ get; set; }
A do místní metody Update
zavoláme Update
u
kamery, pokud ji máme nastavenu:
if (Kamera != null) Kamera.Update();
Hotovo Kamery stejně jako
komponenty přidáme v metodě
Load
a máme vystaráno. Dobré je
ještě zřídit si u komponenty speciální metodu Draw
, kde
budeme v parametrech rovnou předávat naše dvě matice a pozici kamery.
Přesuneme se tedy do třídy s komponentou a tuto metodu přidáme:
public virtual void Draw(Matrix View, Matrix Projection, Vector3 CameraPosition){ }
a v druhé metodě ji zavoláme:
public virtual void Draw(){ if (Parent.Kamera != null){ Draw(Parent.Kamera.View, Parent.Kamera.Projection, Parent.Kamera.Pozice); } }
Výborně. Nyní je vše potřebné hotovo. Máme kameru, jsme na třetí rozměr dobře vybaveni a nebo ne? Opravdu ne. Kameru máme, ale je nepoužitelná bude potřeba si udělat její kamarádku, kterou už použít lze. I když to nebude žádné terno, ale pro začátek to stačí. Kamer bylo vymyšleno hodně. Za všemi se ale skrývá větší případně menší vektorová matematika. Nejsnazší je kamera, kterou jsme již používali při vykreslování v prvních dílech seriálu, anglicky ji najdete pod názvem target camera. Název vypovídá za vše. Kamera má svůj cíl, na který ze své pozice hledí. Free camera nebo také FPS kamera se hýbe tím směrem, kam se dívá. Další je chase camera, tedy kamera která má přiřazený nějaký objekt za kterým v určené vzdálenosti létá. Toto už je matematicky složitější i na pochopení toho jak to vlastně funguje. Občas se hodí i moje oblíbená arc ball camera. To je kamera, která se pohybuje v určité vzdálenosti kolem daného bodu. Hýbe se tedy po pomyslné kouli. Jak se tohoto docílilo se mě neptejte. Nevím to, hlavně že mi to funguje. Jak taková kamera vypadá v akci můžete vidět na následujícím videu:
Target pevná kamera
Zatím nám bude stačit pro naše skromné účely statická
target camera
. Budeme jí třeba říkat pevná kamera. Název
třídy ponechám anglicky, je to vhodné pro případné hledání zdrojů a
informací. Do složky na kamery si tedy přidáme soubor se třídou
TargetKamera
. Jako obvykle učiníme veřejnou, upravíme jmenný
prostor a zařídíme že bude dědit z třídy Kamera:
public class TargetKamera: Kamera
Potřeba bude onen cíl, kam se kamera dívá, takže si jej vytvořme:
private Vector3 fTarget; public Vector3 Target{ get{ return fTarget; } set{ fTarget = value; } }
Přidáme konstruktor:
public TargetKamera(GameScreen okno, Vector3 pozice, Vector3 target):base(okno){ Pozice = pozice; Target = target; }
Nyní zbývá už jenom přepsat metodu Update
, kde budeme
generovat matici View
a to následovně. Pro vytvoření matice
View
použijeme stejnou metodu jako jsme používali dříve:
public override void Update(){ this.View = Matrix.CreateLookAt(Pozice, Target, Vector3.Up); }
A je hotovo.
V příštím díle, XNA tvorba ve 3D - Model podruhé, si přendáme model do komponent a skrze engine si jej vykreslíme. Což si ostatně můžete zkusit udělat i sami. Opět čekám na Vaše komentáře dole pod článkem.
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 223x (1.67 MB)
Aplikace je včetně zdrojových kódů v jazyce C#