9. díl - XNA tvorba ve 3D - Kamera

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

Vítejte podesáté. 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 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.


 

Stáhnout

Staženo 204x (1.67 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 (4 hlasů) :
4.754.754.754.754.75


 


Miniatura
Předchozí článek
XNA tvorba ve 3D - Sprity a Text
Miniatura
Všechny články v sekci
Základy 3D grafiky a tvorba enginu
Miniatura
Následující článek
XNA tvorba ve 3D - Model podruhé

 

 

Komentáře

Avatar
Milan Lhoták:

ahoj, není zbytečné v abstraktu nastavovat projekci v konstruktoru, když tam zároven používáme seter na farplane, kde to nastavujeme znovu?

 
Odpovědět 6. března 23:19
Avatar
Milan Lhoták:

.. jen by to asi chtělo v konstruktoru, nejdřív nastavit rodiče a pak teprve farplane.

 
Odpovědět 6. března 23:34
Avatar
Milan Lhoták:

jej já su hnidopich, to bude tím, že jsem začátečník ve 3d. ještě 1 otázka, proč je update ve třídě okna a draw ve třídě component, má to nějaký význam?

 
Odpovědět 6. března 23:57
Avatar
vodacek
Redaktor
Avatar
Odpovídá na Milan Lhoták
vodacek:

hnidopich trpící samomluvou

  1. asi to zbytečné je
  2. a to je dost možná ten důvod proč se to tam dělá
  3. něco musí kameru updatovat a to svede jen herní okno kterému patří, naopak okno při vykreslení kameru používá
 
Odpovědět 7. března 8:06
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 4 zpráv z 4.