Fonctions de rotation sur plusieurs axes

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
benjamab
Messages : 3
Inscription : 08 Août 2020 10:11

Fonctions de rotation sur plusieurs axes

Message par benjamab » 08 Août 2020 11:32

Bonjour,

je suis sur unity 2020.1.01f, je débute plus ou moins, mais j'ai une bonne expérience de développeur.
Je m'arrache les cheveux pour comprendre la logique des routines de rotation.
Mon problème : je cherche a faire un script attaché à un objet caméra, sans rigibody ni collider, donc normalement sans physique. Le but étant de faire une caméra libre à la première personne. Je veux donc gérer les déplacements (ok avec transform.translate) et les rotations, pour l'instant autours de deux axes x (pitch) et y (yaw).

J'arrive très bien à faire ces rotations séparément avec :

transform.Rotate(transform.up * Input.GetAxis("Mouse X") * horizontalMouseSensibility * Time.deltaTime);

et :

transform.Rotate(transform.right * Input.GetAxis("Mouse Y") * verticalMouseSensibility * Time.deltaTime);

Mais dès que je combine les deux, je me retrouve avec un angle de rotation autour de z (roll) en bonus ! En théorie, vu que je travaille sur les axes locaux up et right de mon game objetct, ceux-ci sont sensés être actualisés à chaque rotation. Il ne devrait jamais y avoir de rotation autour de l'axe local forward.

J'ai essayé un paquet de façon différentes (rotateAround, quaternion, euler, Vector3.up au lieu de transform.up, imbriquer des gamesObject gérant chacun un axe de rotation, passer de local à world), le résultat est toujours le même. J'ai pas mal recherché sur le net à ce propos, mais je n'ai pas trouvé d’explication satisfaisante. Il parait que c'est inhérent à la nature des quaternion, ça ne m'avance pas beaucoup et ça me parait étonnant pour une fonctionnalité aussi basique.

Quelqu'un a-t-il une solution à mon problème, ou une explication sur ce que j'ai sans doute raté sur la logique de la fonction transform.rotate ? D'avance merci.
Dernière édition par benjamab le 09 Août 2020 11:09, édité 2 fois.

Avatar de l’utilisateur
Max
Messages : 8764
Inscription : 30 Juil 2011 13:57
Contact :

Re: Fonctions de rotation sur plusieurs axes

Message par Max » 08 Août 2020 12:18

Bonjour,

soucis souvent évoqué.
Tu as plusieurs solutions pour contourner cet effet indésirtable.
Premier exemple, appliquer la rotation sur l'axe des Y en global, puis sur l'axe des X en local:

Code : Tout sélectionner

        transform.Rotate(0, Input.GetAxisRaw("Mouse X") * mouseSensibility * Time.deltaTime, 0, Space.World);
        transform.Rotate(-Input.GetAxisRaw("Mouse Y") * mouseSensibility * Time.deltaTime, 0, 0, Space.Self);
Autre solution, attaquer directement les angles sur le quaternion:

Code : Tout sélectionner

    Vector3 rotateCam;
    ....
      void Update()
    {
        rotateCam.x = -Input.GetAxisRaw("Mouse Y") * mouseSensibility;
        rotateCam.y = Input.GetAxisRaw("Mouse X") * mouseSensibility;
        transform.eulerAngles += rotateCam * Time.deltaTime;
      }
Image
Pas d'aide par MP, le forum est là pour ça.
En cas de doute sur les bonnes pratiques à adopter sur le forum, consulter la Charte et sa FAQ

benjamab
Messages : 3
Inscription : 08 Août 2020 10:11

Re: Fonctions de rotation sur plusieurs axes

Message par benjamab » 08 Août 2020 13:13

Merci, ta deuxième solution fonctionne parfaitement. C'est la fonction que je cherchais, elle attaque directement les degrés de rotation affichés dans l'UI d'Unity. J'étais passé à côté. Il y a juste un problème de lock à 90 et -90° de l'angle autour de x, dont j'avais déjà entendu parlé. Je vais voir ce que je peux faire la dessus.

Pour ceux que ça intéresse, voici le code qui gère la rotation sur 3 axes.

Code : Tout sélectionner

public class FreeFirstPersonCamera : MonoBehaviour
{
    [SerializeField]
    private float rollSpeed = 20f;
    [SerializeField]
    private float horizontalMouseSensibility = 250f;
    [SerializeField]
    private float verticalMouseSensibility = 250f;
    [SerializeField]
    private bool invertedVeticalMouse = false;

    private Vector3 cameraRotation = new Vector3(0, 0, 0);

    void Awake()
    {
        cameraRotation = transform.eulerAngles;
    }

    // Update is called once per frame
    void Update()
    {
        if (invertedVeticalMouse)
        {
            cameraRotation.x = Input.GetAxis("Mouse Y") * verticalMouseSensibility;
        }
        else
        {
            cameraRotation.x = -Input.GetAxis("Mouse Y") * verticalMouseSensibility;
        }       
        cameraRotation.y = Input.GetAxis("Mouse X") * horizontalMouseSensibility;
        cameraRotation.z = 0;
        if (Input.GetKey(KeyCode.Q))
        {
            cameraRotation.z = rollSpeed;
        }
        if (Input.GetKey(KeyCode.E))
        {
            cameraRotation.z = -rollSpeed;
        }
        transform.eulerAngles = transform.eulerAngles + cameraRotation * Time.fixedDeltaTime;
    }
}

benjamab
Messages : 3
Inscription : 08 Août 2020 10:11

Re: Fonctions de rotation sur plusieurs axes

Message par benjamab » 09 Août 2020 11:56

Après réflexion, ça ne marche pas si bien que ça :oops:

La première méthode fonctionne tant qu'on ne rajoute pas la gestion du troisième axe de rotation autour du z (roll).

La seconde, en plus du gimbal lock à 90° autours du x (pitch) que je n'arrive pas à régler, je me rend compte que plus la rotation autour de x augmente, plus cela affecte la rotation autour de y. A priori la rotation autours de x ne mets pas à jour l'axe de rotation y. Pour schématiser, lorsque l'objet est orienté vers le sol et que je veux tourner à gauche ou à droite, il y a un effet "je regarde à mes pieds et je tourne sur moi même", ce qui n'est pas le but.
Normalement, lorsque je fais une rotation de 90° vers le sol donc sur l'axe local right (x) de mon objet, l'axe local up (y) de l'objet doit se retrouver "parallèle" au sol, là il reste clairement "perpendiculaire".
Il semble qu'en passant par euler, on a le même résultat qu'avec une des méthodes conseillée pour gérer mon problème initial, c'est à dire imbriquer des empty gameObjetct pour chaque niveau de rotation : yaw parent de pitch, lui même parent de roll. Yaw fera uniquement des rotation autour de son axe up, pitch uniquement autour de son axe right et roll, uniquement atour de son axe z.
Cela règle mon problème de roll non désiré lorsque je ne me déplace que sur les axes up et right, mais cela fait également cet effet "je regarde à mes pieds". Cela s'explique, car les axes de l'objet parent yaw ne sont pas affectés par une rotation de son fils pitch.
Bref, je n'ai toujours pas de solution idéale.

Répondre

Revenir vers « Scripting »