Come posso orbitare una telecamera sul suo punto di destinazione?


18

Sto disegnando una scena in cui la telecamera si muove liberamente nell'universo. La classe della telecamera tiene traccia del punto di vista (o dello sguardo ), della posizione della telecamera e del vettore verso l'alto. Questi vettori / punti vengono quindi passati a gluLookAt.

Pan e zoom sono quasi banali da implementare. Tuttavia, mi sto trovando rotazione intorno sguardo al punto di essere molto più di un problema. Voglio scrivere una funzione Camera.rotate che richiede 2 angoli, uno che ruota su / giù e uno che ruota a sinistra / destra lungo una sfera immaginaria che è centrata sullo sguardo nel punto.

C'è un modo semplice per farlo?

Ho (brevemente) letto dei quaternioni, ma volevo vedere se c'era una soluzione più semplice data la costruzione relativamente semplice della mia scena.


Hai qualcosa nella tua cassetta degli attrezzi per ruotare un punto attorno all'origine, dato un asse e un angolo?
Sam Hocevar,

Nient'altro che la mia libera comprensione dei Quaternioni, no. Più sto guardando questo, penso che i Quaternioni potrebbero essere la risposta. Tuttavia, non sono sicuro di come calcolare i valori degli assi x, y e z da utilizzare nelle formule Quaternion.
Luca,

Non ti dirò che i quaternioni non sono la strada da percorrere. Sono un'ottima soluzione al tuo problema. Ma avrai bisogno di una classe quaternione e di modi per interagire con GL e GLU, e sento che dovresti prima provare a familiarizzare con le matrici di trasformazione. Altri potrebbero non essere d'accordo.
Sam Hocevar,

considera in che ordine fai le rotazioni. l'applicazione delle rotazioni per spostarti nello spazio del mondo o per spostarti nello spazio della telecamera differisce
Charlie

Risposte:


25

Quello che stai chiedendo si chiama rotazione Arcball. I quaternioni sono la soluzione semplice solo se capisci come funzionano. Tuttavia, puoi ottenere lo stesso risultato senza quaternioni.

Pre-requisiti

Sai come ruotare gli oggetti in generale? Supponiamo che tu abbia un oggetto all'origine. Sai come ruotarlo (suggerimento: moltiplicare per una matrice di rotazione)? Se sì, allora presumo che tu sappia cosa succederà se traduci prima l'oggetto e poi lo ruoti?

Devi sapere come calcolare una matrice di rotazione dall'asse dell'angolo (facile come una torta, guarda la miriade di equazioni online, molte di esse ti danno anche il codice)

Soluzione

  • Ottieni i vettori su e destra della fotocamera . Si noti che dovrebbero essere normalizzati.
  • Ottieni il vettore dal punto AF alla telecamera (camPosition - Focus). Questo è il vettore che ruoterai. Chiamiamo questo camFocusVector .
  • Decidi di quanto vuoi ruotare in imbardata / inclinazione rispetto alla videocamera
  • Crea due matrici di rotazione. La 1a matrice di rotazione utilizzerà la parte superiore della telecamera come asse e angolo di imbardata decisi. La matrice di 2 ° di rotazione utilizzerà il destro della telecamera come asse e passo angolo che avete deciso.
  • Ora ruota camFocusVector con le nuove matrici di rotazione. Questa è ora la tua nuova posizione della telecamera rispetto all'origine. Ovviamente, vogliamo che sia relativo al punto di messa a fuoco ...
  • Aggiungi la posizione del punto AF a camFocusVector . Questa è ora la nuova posizione della fotocamera. Traduci la tua fotocamera di conseguenza.
  • Infine, chiedi alla fotocamera di mettere a fuoco il punto AF chiamando la tua funzione lookAt ()

Avvertenze

Dovrai cercare determinati casi o singolarità in cui la fotocamera smetterà di funzionare. Guardando verso il basso / verso l'alto, ad esempio. Ti farò capire come gestirli.

EDIT1: come ricalcolare i vettori ortonormali della fotocamera

Conosci già la direzione della videocamera ((cameraPos - focusPoint) .normalize ()). Ora supponi che la tua fotocamera sia + Y (o w / e l'asse up attuale del tuo mondo è ... dipende da te). Ora basta semplicemente attraversare la direzione con la freccia in alto per ottenere la giusta . Fatto? No! Il tuo vettore up non è più ortogonale agli altri due. Per rimediare, croce a destra con direzione e si ottiene il nuovo up .

Si noti che Gram-Schmidt è davvero ciò che dovrebbe essere usato per ortonormalizzare i vettori.

Ancora una volta, prendere nota delle avvertimenti come questo non riuscirà a lavorare in alcuni casi ( direzione è parallela al piano per esempio).


Si noti che il vettore giusto può essere ottenuto usando normalize(up ^ camFocusVector)(o il suo contrario se mancino).
Sam Hocevar,

Finora sembrava buono, ha funzionato magnificamente per la rotazione sinistra / destra (ho il vettore in alto, quindi è facile). Cosa significa '^' nel tuo commento @SamHocevar? È un prodotto incrociato? Inoltre, come posso ricalcolare il vettore up dopo aver effettuato le traduzioni?
Luca,

@Luke: Controlla il mio EDIT1
Samaursa

1
@Samaursa Grazie mille. La tua soluzione funziona perfettamente e ho imparato molto nel processo!
Luca,

2
questa è una risposta ECCELLENTE, grazie mille per la tua spiegazione. Nel mio caso, volevo che la telecamera ruotasse solo attorno al punto target nel piano XY, quindi dopo aver fatto tutti i calcoli, ho sempre impostato cameraRight.z su 0 e quindi ho calcolato il vettore cameraUp. Questo ha dato l'effetto desiderato. Ho solo pensato di condividere
codemonkey il

1

Ciò di cui hai bisogno è una tipica fotocamera ArcBall, che è fondamentalmente una fotocamera che mantiene una posizione target e ti consente di spostare la fotocamera in modo "sferico" attorno a quel target.

È in XNA ma IIRC ho già usato questa implementazione e ha funzionato abbastanza bene:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/


Quell'implementazione sembra muoversi solo direttamente lungo il vettore giusto, che approssimerà un arco per piccoli valori di quantità . Sta anche spostando il punto LookAt, come dove voglio spostare la videocamera (vicino, ma leggermente diverso). Credo che Samaursa abbia fornito il modo più semplice per raggiungere questo obiettivo.
Luca

Grazie per il tuo feedback. Devo ammettere che ho usato questa implementazione un po 'come una "scatola nera" ma non ho notato alcun problema. Per chiarire stavi forse parlando dei metodi MoveCameraRight / MoveCameraForward? Tali metodi sono stati aggiunti per spostare la telecamera, ma non fanno parte dell'interfaccia Arcball. Se si desidera ruotare la videocamera attorno al bersaglio, è sufficiente modificare le proprietà di imbardata o inclinazione.
David Gouveia,

Scusa, hai ragione, quelli sono metodi di panning. Non ho notato come ha impostato una bandiera sporca per la matrice quando sono stati cambiati imbardata e beccheggio.
Luca,

0

Ecco il mio codice per ruotare attorno a un punto, mi sono ritrovato a riutilizzarlo molto.

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector

1
Questo è sostanzialmente il modo in cui l'ho fatto inizialmente. Ci sono molti problemi nel farlo in questo modo (almeno per me). Fondamentalmente questa implementazione ruota solo di circa 2 assi fissi. Diciamo che si ruota fino quasi al polo nord . Quindi ruota a destra . Ti ritroverai a girare in un piccolo cerchio piuttosto che seguire il vettore giusto della videocamera per tutto il mondo .
Luca

Ora che me lo hai detto, immagino che ci siano due modi diversi di esaminare il problema. Nella mia applicazione ho usato la telecamera ArcBall per ruotare attorno a un'isola bersaglio sul mare e se avessi usato 3 assi di libertà, sarebbe sembrato chiaramente sbagliato (come vedere l'isola capovolta o lateralmente).
David Gouveia,

Come posso ottenere gli angoli della fotocamera qui?
rafvasq,

0

Questo algoritmo semplicissimo da ottenere è davvero fantastico:

Essendo P il punto centrale su di te che vuoi ruotare (il punto "guarda" o "bersaglio"):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

L'ho usato ed è bello.

Fonte trovata nello stackoverflow del sito gemello: /programming/287655/opengl-rotating-a-camera-around-a-point

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.