Rotation de la caméra 3D

9

S'il vous plaît, pardonnez-moi, mais j'ai besoin d'aide et je suis coincé là-dessus depuis quelques semaines maintenant, je ne fais aucun progrès et partout où je vais et je vois une réponse différente, tout ce que j'essaie ne fonctionne pas. J'ai eu assez de trucs et de conseils, maintenant j'ai vraiment juste besoin de quelqu'un pour me donner la réponse pour que je puisse travailler à l'envers parce que je ne comprends pas cela.

Ce qui a rendu ce sujet le plus déroutant, c'est la façon dont chacun utilise un ensemble différent de conventions ou de règles, et leurs réponses sont basées sur leurs propres conventions sans définir ce qu'elles sont.

Voici donc l'ensemble des conventions que j'ai formées sur la base de ce qui semble être le plus courant et le plus logique:

  1. Règle de droite pour l'axe.
  2. Positive Y est en haut, Positive Z est vers le spectateur, Positive X est à droite.
  3. Matrices de lignes principales, transposées lorsqu'elles sont envoyées aux shaders.
    • Pas: rotation autour de l'axe X
    • Lacet: rotation autour de l'axe y
    • Roll: rotation autour de l'axe z
  4. Ordre de rotation: roulis, tangage, lacet (est-ce correct? Quelqu'un peut-il me vérifier à ce sujet?)
  5. Les valeurs de rotation positive, regardant vers le bas depuis l'extrémité positive d'un axe, entraînent une rotation dans le sens horaire.
  6. La direction par défaut pour une rotation de 0 sur tous les axes est un vecteur pointant vers Y négatif.

.. étant donné ces conventions (corrigez-moi bien sûr si elles sont erronées!), comment peut-on:

  • Écrire une fonction LookAt? (lookAt (position vectorielle, mise au point vectorielle, vecteur vers le haut))
  • Calculez une matrice de rotation. (rotation (x, y, z))

J'ai essayé de répondre à ces deux questions moi-même au moins au cours des 3 dernières semaines, j'ai réécrit ma fonction LookAt & Rotation Matrix au moins 30 fois, j'ai testé des dizaines de méthodes et lu des documents que j'ai vus sur des centaines de sites Web et lu de nombreuses réponses aux questions, copié le code d'autres personnes, et rien de ce que j'ai fait jusqu'à présent n'a fonctionné, tout a produit le mauvais résultat. Certains d'entre eux ont produit des sorties hilarantes bizarres qui ne sont même pas proches d'une rotation correcte.

J'y travaille tous les soirs à l'exception de la nuit dernière parce que j'étais tellement frustré par l'échec répété que j'ai dû m'arrêter et faire une pause.

S'il vous plaît, montrez-moi simplement quelle est la bonne méthode afin que je puisse travailler en arrière à partir de cela et comprendre comment cela fonctionne, je n'obtiens tout simplement pas la bonne réponse et cela me rend un peu fou!

J'écris en Java mais je prendrai du code écrit dans n'importe quel langage, la plupart de mon code de rendu 3D fonctionne en fait de manière très brillante, c'est juste les mathématiques que je ne peux pas comprendre.

MISE À JOUR: RÉSOLU

Merci de votre aide! J'ai maintenant une fonction LookAt fonctionnelle que je comprends réellement et je ne pourrais pas être plus heureux (si quelqu'un souhaite le voir par tous les moyens).

J'ai essayé à nouveau de créer une matrice de rotation basée sur des variables de tangage / lacet / roulis et cela a semblé à nouveau échouer, mais j'ai décidé de vider en essayant d'utiliser les angles d'Euler pour la caméra Freelook car elle semble mal adaptée au Au lieu de cela, je vais créer une classe de quaternion, j'aurais plus de chance de suivre cette voie, sinon je vais utiliser le tangage / lacet comme coordonnées sphériques et compter sur la nouvelle fonction LookAt fonctionnelle pour la rotation.

Si quelqu'un d'autre est confronté à un problème similaire et veut me poser des questions, n'hésitez pas à le faire.

Au moins, je ne suis plus coincé, merci pour l'aide!

Grady
la source

Réponses:

15

Ce que vous recherchez se trouve dans cette très bonne explication: http://www.songho.ca/opengl/gl_transform.html

Mais comme je l'ai trouvé un peu déroutant sans tenir la main, je vais essayer de l'expliquer ici.

À ce stade, vous devez considérer 5 systèmes de coordonnées et comment ils se rapportent les uns aux autres. Ce sont les coordonnées de la fenêtre, les coordonnées normalisées de l'appareil, les coordonnées de l'œil, les coordonnées du monde et les coordonnées de l'objet.

Les coordonnées de la fenêtre peuvent être vues comme les pixels "physiques" de votre écran. Ce sont les coordonnées auxquelles le système de fenêtrage fait référence et si vous utilisez la résolution native de votre moniteur, ce sont en fait des pixels individuels. Le système de coordonnées de la fenêtre est un entier 2D et est relatif à votre fenêtre. Ici, le x + est à gauche et y + est en bas avec l'origine dans le coin supérieur gauche. Vous les rencontrez lorsque vous appelez par exempleglViewport .

Le deuxième ensemble sont les coordonnées normalisées de l'appareil. Ceux-ci se réfèrent à la configuration de l'espace par le port de vue actif. La zone visible du port de vue passe de -1 à +1 et a donc l'origine au centre. Le x + est à gauche et le y + est à la hausse. Vous avez également le z + est "hors" de la scène. C'est ce que vous décrivez en 1.

Vous n'avez aucun contrôle sur la façon dont vous passez des coordonnées normalisées de l'appareil aux coordonnées de la fenêtre, cela se fait implicitement pour vous. Le seul contrôle que vous avez est à traversglViewport ou similaire.

Lorsque vous travaillez avec openGL, votre résultat final sera toujours en coordonnées de périphérique normalisées. Par conséquent, vous devez vous soucier de la façon dont votre scène doit être rendue. Si vous définissez la matrice de projection et de vue du modèle sur la matrice d'identité, vous pouvez directement dessiner ces coordonnées. Cela se fait par exemple lors de l'application d'effets en plein écran.

Le suivant est les coordonnées de l'œil. C'est le monde vu de la caméra. En conséquence, l'origine se trouve dans la caméra et les mêmes aliments d'axe comme les coordonnées de l'appareil s'appliquent.

Pour passer des coordonnées de l'œil aux coordonnées de l'appareil, vous créez la matrice de projection. La plus simple est la projection orthographique qui met à l'échelle les valeurs de manière appropriée. La projection en perspective est plus compliquée et implique une perspective de simulation.

Enfin, vous avez le système de coordonnées mondial. Il s'agit du système de coordonnées dans lequel votre monde est défini et votre caméra fait partie de ce monde. Ici, il est important de noter que les orientations des axes sont exactement telles que vous les définissez . Si vous préférez z +, c'est très bien.

Pour passer des coordonnées du monde aux coordonnées de l'œil, vous définissez la matrice de vue. Cela peut être fait avec quelque chose comme lookAt. Ce que cette matrice fait, c'est "déplacer" le monde de sorte que la caméra soit à l'origine et regarde vers le bas sur l'axe z.

Pour calculer la matrice de vue est étonnamment simple, vous devez effectuer la transformation de la caméra. Vous devez essentiellement formuler la matrice suivante:

M=X[1]y[1]z[1]-p[1]X[2]y[2]z[2]-p[2]X[3]y[3]z[3]-p[3]0001

Les vecteurs x, y et z peuvent être directement extraits de la caméra. Dans le cas du regard, vous les dériveriez de la cible, de l'œil (centre) et des valeurs supérieures. Ainsi:

z=normuneljeze(eye-tunerget)X=normuneljeze(up×z)y=zX

Mais si vous avez ces valeurs qui traînent, vous pouvez simplement les prendre telles quelles.

Obtenir p est un peu plus délicat. Ce n'est pas la position en coordonnées mondiales mais la position en coordonnées de caméra. Une solution de contournement simple ici consiste à initialiser deux matrices, une avec seulement x, y et z et une seconde avec -eye et à les multiplier ensemble. Le résultat est la matrice de vue.

Pour savoir à quoi cela peut ressembler dans le code:

mat4 lookat(vec3 eye, vec3 target, vec3 up)
{
    vec3 zaxis = normalize(eye - target);    
    vec3 xaxis = normalize(cross(up, zaxis));
    vec3 yaxis = cross(zaxis, xaxis);     

    mat4 orientation(
       xaxis[0], yaxis[0], zaxis[0], 0,
       xaxis[1], yaxis[1], zaxis[1], 0,
       xaxis[2], yaxis[2], zaxis[2], 0,
         0,       0,       0,     1);

    mat4 translation(
              1,       0,       0, 0,
              0,       1,       0, 0, 
              0,       0,       1, 0,
        -eye[0], -eye[1], -eye[2], 1);

    return orientation * translation;
}

code complet

Et enfin, par souci d'exhaustivité, vous avez également le système de coordonnées d'objet. Il s'agit du système de coordonnées dans lequel les maillages sont stockés. À l'aide de la matrice du modèle, les coordonnées du maillage sont converties dans le système de coordonnées mondial. En pratique, les matrices de modèle et de vue sont combinées dans la matrice dite de vue de modèle.

rioki
la source
1
Si je pouvais voter cent fois pour cette réponse, je le ferais. Merci pour une réponse complète et complète abordant tout ce qui m'a dérouté et en fournissant le code et le lien aussi! J'ai passé toute la journée à lire des livres de mathématiques sur ce sujet et avec votre réponse et l'exemple de code et la page liée, si cela ne me suffit pas pour comprendre cela, je devrais arrêter maintenant. Si je pouvais demander une seule précision, dans ce dernier échantillon de code, aurais-je raison de dire que ces matrices sont dans l'ordre des colonnes et que celle ci-dessus est dans les lignes principales?
Grady
C'est un peu confus, les matrices sont des colonnes majeures, mais la colonne est dans la ligne. Donc, pour mapper les mathématiques réelles au code, vous devez transposer la matrice. Voir github.com/rioki/glm/blob/master/src/matrix.h#l72 Ceci correspond exactement à openGL et comment ce serait en cas d'utilisation float[16].
rioki
Ah, je le pensais, mais je voulais juste en être sûr, merci encore! Vous avez été d'une grande aide, je l'apprécie vraiment.
Grady