Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 46 di 53
  • livello principiante
Indice lezioni

La telecamera in una scena 3D

Disegnare una scena composta iniziando con un solo oggetto tridimensionale
Disegnare una scena composta iniziando con un solo oggetto tridimensionale
Link copiato negli appunti

Per capire come funziona la telecamera, disegneremo una semplice scena composta da un solo oggetto tridimensionale (vedremo in un successivo articolo come funzionano nel dettaglio i modelli 3D, per adesso ci basti sapere che questi sono rappresentati in XNA mediante la classe Model, la quale espone un metodo Draw che, per renderizzare un modello a schermo richiede, come parametri, le matrici World, View e Projection).

Dichiariamo dunque il nostro modello 3D e carichiamolo all'interno del progetto di tipo Content:

Model tank;
tank = Content.Load("tank");

World

Creiamo adesso una matrice per collocare il nostro oggetto tridimensionale sulla scena e fissiamo la sua posizione al centro del sistema di coordinate. Per far questo, è sufficiente utilizzare il metodo Identity esposto dalla struttura Matrix, il quale restituisce una cosiddetta matrice di identità, ossia una matrice composta unicamente da zeri e con la diagonale principale impostata tutta a 1.

Matrix world = Matrix.Identity;

Projection

Per quanto riguarda invece il campo visivo della telecamera, impostiamo l'angolo di apertura a un classico 45°, mentre per l'aspect ratio utilizziamo quello del nostro device (GraphicsDevice.Viewport.AspectRatio). Infine, fissiamo una "profondità di campo" particolarmente generosa, ricompresa tra 1 e 10.000.

Bisogna terer presente che tutto ciò che si trova all'interno questi valori dovrà essere disegnato a schermo, impegnando le risorse hardware del nostro device; inoltre un campo troppo ampio non è in grado di rappresentare valori piccoli di Z correttamente: con un range [1..10000] valori di Z come 1.1 e 1.2 saranno trattati come uguali e superfici con tale Z potranno sovrapporsi o soffrire di flickering o z-fighting.

Matrix projection = Matrix.CreatePerspectiveFieldOfView(
      MathHelper.PiOver4,
	  GraphicsDevice.Viewport.AspectRatio, 1, 10000);

Nel metodo Draw della classe Game, disegnamo la nostra scena tridimensionale usando il relativo metodo esposto dalla classe Model, passando come parametri i valori delle matrici world, view e projection:

tank.Draw(world, view, projection);

View

L'ultima cosa che ci manca prima di poter disegnare il nostro modello di carro armato è definire la matrice View, che come si è detto rappresenta la posizione e l'orientamento della telecamera rispetto al mondo circostante. Per la posizione, collochiamo la telecamera in posizione sollevata rispetto all'oggetto da renderizzare e arretrata rispetto all'asse delle Z, aumentanto così la distanza dal modello.

Vector3 position = Vector3.Up * 200.0f + Vector3.Backward * 400.0f;

In XNA esistono una serie di vettori unitari predefiniti (i cosiddetti versori), solitamente utilizzati per indicare una particolare direzione nello spazio:

Versore Valore Direzione
Vector3.Up (0, 1, 0) verso l'alto
Vector3.Backward (0, 0, 1) verso l'osservatore
Vector3.Forward (0, 0, -1) verso l'interno dello schermo

La rotazione della telecamera rispetto ai suoi assi è invece rappresentata mediante un cosiddetto Quaternione, ossia un "oggetto" matematico simile alla matrice (ma relativamente più semplice) in grado di esprimere una rotazione di un agolo qualsiasi intorno a uno qualunque dei tre assi X, Y e/o Z.

Rispetto alle matrici di rotazione, il quaternione consente di creare interpolazioni fluide tra due angoli, evitando il cosiddetto "Gimbal lock" (o "blocco cardanico"), che si ha quando si combinano due o più rotazioni intorno a differenti assi (il secondo asse è infatti ruotato dalla rotazione intorno al primo asse, mentre il terzo risulterà da una combinazione delle prime due rotazioni, con risultati imprevedibili).

In XNA, le rotazioni intorno ai tre assi prendono il loro nome dal campo areonautico (Figura 4): si parla dunque di:

  • yaw, per esprimere la rotazione intorno all'asse verticale (Y)
  • pitch, per indicare la rotazione intorno all'asse laterale (X)
  • roll, per la rotazione intorno all'asse longitudinale (Z)
Figura 4. Rotazione della telecamera intorno agli assi
Rotazione della telecamera intorno agli assi

Per la nostra demo, impostiamo una rotazione pari a 0 utilizzando il metodo Identity della struttura Quaternion:

Quaternion rotation = Quaternion.Identity;

Adesso possiamo assegnare questi valori alla nostra matrice View, ricordandoci di invertirli. Occorre infatti tener presente che una telecamera è in realtà ottenuta come trasformazione dei vertici del mondo. Se l'osservatore fa un passo a sinistra, è in realtà la scena stessa a muoversi verso destra di un passo; analogamente, quando la telecamera ruota intorno ad un oggetto, ciò che in realtà avviene è una rotazione del mondo in senso contrario.

Matrix view = Matrix.CreateTranslation(-position) * Matrix.Inverse(Matrix.CreateFromQuaternion(rotation));

Il metodo CreateFromQuaternion provvede a convertire il quaternione usato per memorizzare la rotazione in una corrispondente matrice. Il metodo Inverse provvede poi a invertire l'angolo di rotazione. Dal momento che questa operazione è piuttosto "pesante", possiamo utilizzare una relazione nota nell'algebra delle matrici per cui l'inversa di una rotazione equivale alla sua trasposta (si tratta di una equivalenza che è in falsa per le matrici in generale, ma risulta valida per le rotazioni), molto più veloce da calcolare rispetto alla prima.

Matrix view = Matrix.CreateTranslation(-position) * Matrix.Transpose(Matrix.CreateFromQuaternion(rotation));

Ti consigliamo anche