Comment puis-je orbiter une caméra autour de son point cible?

18

Je dessine une scène où la caméra se déplace librement dans l'univers. La classe de caméra garde une trace du point de vue (ou de regard ), de la position de la caméra et du vecteur haut. Ces vecteurs / points sont ensuite passés dans gluLookAt.

Le panoramique et le zoom sont presque triviaux à mettre en œuvre. Cependant, je trouve rotation autour de l' oeil à point de d'être beaucoup plus d'un problème. Je veux écrire un Camera.rotate fonction qui prend 2 angles, qui tourne vers le haut / vers le bas et qui tourne à gauche / droite le long d' une sphère imaginaire centrée sur le regard sur le point.

Y a-t-il un moyen facile de faire ceci?

J'ai (brièvement) lu sur les quaternions, mais je voulais voir s'il y avait une solution plus facile étant donné la construction relativement simple de ma scène.

Luc
la source
Avez-vous quelque chose dans votre boîte à outils pour faire pivoter un point autour de l'origine, étant donné un axe et un angle?
sam hocevar
Rien d'autre que ma compréhension vague des Quaternions, non. Plus je regarde ça, je pense que les Quaternions pourraient être la réponse. Cependant, je ne sais pas comment calculer les valeurs des axes x, y et z à utiliser dans les formules Quaternion.
Luke
Je ne vous dirai pas que les quaternions ne sont pas la voie à suivre. Ils sont une très bonne solution à votre problème. Mais vous aurez besoin d'une classe quaternion et de moyens d'interagir avec GL et GLU, et je pense que vous devriez d'abord essayer de vous familiariser avec les matrices de transformation. D'autres peuvent être en désaccord.
sam hocevar
considérez l'ordre dans lequel vous effectuez les rotations. appliquer des rotations pour se déplacer vers l'espace mondial ou pour se déplacer vers l'espace de la caméra diffère
Charlie

Réponses:

25

Ce que vous demandez s'appelle la rotation Arcball. Les quaternions ne sont la solution facile que si vous comprenez comment ils fonctionnent. Vous pouvez cependant obtenir la même chose sans quaternions.

Conditions préalables

Savez-vous comment faire pivoter des objets en général? Disons que vous avez un objet à l'origine. Savez-vous comment vous le faites pivoter (indice: multipliez par une matrice de rotation)? Si oui, je suppose que vous savez ce qui se passera si vous traduisez d'abord l'objet, puis le faites pivoter?

Vous devez savoir comment calculer une matrice de rotation à partir de l'angle-axe (simple comme bonjour, regardez la myriade d'équations en ligne, beaucoup d'entre elles vous donnent également le code)

Solution

  • Obtenez les vecteurs haut et droit de la caméra . Notez qu'ils doivent être normalisés.
  • Obtenez le vecteur du point AF à la caméra (camPosition - Focus). C'est le vecteur que vous allez faire tourner. Appelons ce camFocusVector .
  • Décidez à quel point vous souhaitez faire pivoter en lacet / tangage par rapport à la caméra
  • Créez deux matrices de rotation. La 1ère matrice de rotation utilisera le haut de la caméra comme axe et angle de lacet que vous avez décidé. La 2ème matrice de rotation utilisera la droite de la caméra comme axe et angle de tangage que vous avez décidé.
  • Faites maintenant tourner le camFocusVector avec les nouvelles matrices de rotation. C'est maintenant votre nouvelle position de la caméra par rapport à l'origine. Nous voulons bien sûr que cela soit relatif au point focal ...
  • Ajoutez la position du point AF à camFocusVector . C'est maintenant la nouvelle position de votre caméra. Traduisez votre appareil photo en conséquence.
  • Enfin, demandez à la caméra de se concentrer sur le point AF en appelant votre fonction lookAt ()

Avertissements

Vous devrez rechercher certains cas ou singularités auxquels votre appareil photo cessera de fonctionner. Regarder vers le bas / haut par exemple. Je vais vous laisser comprendre comment y faire face.

EDIT1: Comment recalculer les vecteurs orthonormaux de la caméra

Vous connaissez déjà la direction de la caméra ((cameraPos - focusPoint) .normalize ()). Supposons maintenant que le haut de votre appareil photo soit + Y (ou w / e l'axe actuel de votre monde est ... c'est à vous de décider). Maintenant, traversez simplement la direction avec le haut pour obtenir la bonne . Terminé? Nan! Votre vecteur haut n'est plus orthogonal aux deux autres. Pour résoudre ce problème, croix à droite avec la direction et vous obtenez votre nouvelle place .

Notez que le Gram-Schmidt est vraiment ce qui devrait être utilisé pour orthonormaliser des vecteurs.

Encore une fois, notez les mises en garde car cela ne fonctionnera pas dans certains cas (la direction est parallèle à up par exemple).

Samaursa
la source
Notez que le vecteur droit peut être obtenu en utilisant normalize(up ^ camFocusVector)(ou son opposé s'il est gaucher).
sam hocevar
En regardant bien jusqu'à présent, cela fonctionnait magnifiquement pour la rotation gauche / droite (j'ai le vecteur haut donc c'est facile). Que signifie le «^» dans votre commentaire @SamHocevar? Est-ce un produit croisé? Aussi, comment puis-je recalculer le vecteur up une fois que j'ai fait les traductions?
Luke
@Luke: Check my EDIT1
Samaursa
1
@Samaursa Merci beaucoup. Votre solution fonctionne parfaitement et j'ai beaucoup appris au cours du processus!
Luke
2
c'est une EXCELLENTE réponse, merci beaucoup pour votre explication. Dans mon cas, je voulais que la caméra tourne uniquement autour du point cible dans le plan XY, et donc après avoir fait tous les calculs, j'ai toujours défini cameraRight.z sur 0, puis calculé le vecteur cameraUp. Cela a donné l'effet souhaité. Juste pensé à partager
codemonkey
1

Ce dont vous avez besoin est une caméra ArcBall typique, qui est fondamentalement une caméra qui conserve un emplacement cible et vous permet de déplacer la caméra de manière "sphérique" autour de cette cible.

C'est dans XNA mais IIRC J'ai déjà utilisé cette implémentation, et cela a plutôt bien fonctionné:

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

David Gouveia
la source
Cette implémentation ne semble se déplacer directement que le long du vecteur de droite, qui se rapprochera d'un arcball pour les petites valeurs de quantité . Il déplace également le point LookAt, comme l'endroit où je veux déplacer la caméra (proche, mais subtilement différent). Je crois que Samaursa a fourni le moyen complet le plus simple d'y parvenir.
Luke
Merci pour votre avis. Je dois admettre que j'ai utilisé un peu cette implémentation comme une "blackbox" mais je n'ai pas remarqué de problème. Pour clarifier, parliez-vous peut-être des méthodes MoveCameraRight / MoveCameraForward? Ces méthodes ont été ajoutées afin de déplacer la caméra, mais ne font pas partie de l'interface Arcball. Si vous souhaitez faire pivoter la caméra autour de la cible, il vous suffit de modifier les propriétés de lacet ou de tangage.
David Gouveia
Désolé, vous avez raison, ce sont des méthodes de panoramique. Je n'ai pas remarqué comment il a mis un drapeau sale pour la matrice lorsque le lacet et le tangage ont été modifiés.
Luke
0

Voici mon code pour tourner autour d'un point, je me suis retrouvé à le réutiliser beaucoup.

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
Stephen Tierney
la source
1
C'est essentiellement la façon dont je l'ai fait au départ. Il y a beaucoup de problèmes à le faire de cette façon (du moins pour moi). Fondamentalement, cette mise en œuvre ne tourne que d'environ 2 axes fixes. Disons que vous faites pivoter jusqu'à près du pôle nord . Tournez ensuite à droite . Vous vous retrouverez à tourner dans un petit cercle plutôt que de suivre le bon vecteur de la caméra tout autour du globe .
Luke
Maintenant que vous l'avez mentionné, je suppose qu'il y a deux façons différentes de considérer le problème. Dans mon application, j'ai utilisé la caméra ArcBall pour tourner autour d'une île cible sur la mer, et si j'utilisais 3 axes de liberté, cela aurait l'air tout à fait faux (comme voir l'île à l'envers ou latéralement).
David Gouveia
Comment obtenir les angles de caméra ici?
rafvasq
0

Cet algorithme très simple pour y parvenir est assez génial:

En étant P le point central sur lequel vous voulez faire pivoter (le point "regardez" ou "cible"):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

Je l'ai utilisé et c'est sympa.

Source trouvée sur le site sœur stackoverflow: /programming/287655/opengl-rotating-a-camera-around-a-point

diosney
la source