[Resolu][MY-AL]Rotation dans une boule

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
EmileF
Messages : 676
Inscription : 18 Mars 2017 19:39

[Resolu][MY-AL]Rotation dans une boule

Message par EmileF » 22 Jan 2019 16:39

Bonjour

J'ai besoin d'un peu d'aide, imaginons que je suis au centre d'une boule.
Je vois autour de moi l'intérieur de cette boule, en fait comme une SkyShere, mais en plus petit.
Je voudrais faire pivoter cette boule dans tous les sens avec la souris.
Je n'ai aucune idée de comment m'y prendre.
Si quelqu’un pouvait me guider une peu, ce serait formidable.

Merci d'avance.
Dernière édition par EmileF le 23 Jan 2019 19:09, édité 1 fois.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6220
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [MY-AL]Rotation dans une boule

Message par boubouk50 » 22 Jan 2019 17:35

Comme une navigation à l'intérieur d'une vidéo 360°? -> rotation unique aux pôles
Ou plutôt une rotation externe (locale caméra) pour tourner selon 2 axes en continu?

Concernant les fonctions: Input.GetAxis
Je viens de voir l'exemple (le dernier) de la doc, ça te donne une bonne idée du lien entre rotation et axes.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

EmileF
Messages : 676
Inscription : 18 Mars 2017 19:39

Re: [MY-AL]Rotation dans une boule

Message par EmileF » 22 Jan 2019 21:40

Boubouk a écrit : Comme une navigation à l'intérieur d'une vidéo 360°? -> rotation unique aux pôles
oui mis à part que la rotation doit pouvoir se faire sur les 3 axes.
Boubouk a écrit : Ou plutôt une rotation externe (locale caméra) pour tourner selon 2 axes en continu?
Sauf que la commande vient de l'intérieur de la sphère.
Boubouk a écrit : Concernant les fonctions: Input.GetAxis
Je viens de voir l'exemple (le dernier) de la doc, ça te donne une bonne idée du lien entre rotation et axes.
Ca c'est bon. Je connais.

Je travaille sur ce problème depuis hier.
J'ai trouvé une solution qui marche à peu près.

Devant ma caméra. j'ai mis 9 quads avec le render désactivé en mode game, pour capturer les clics et mouvement de la souris.
et selon le quad sur lequel je clique et drag, le sphere fait une rotation qui suit la souris. Je ne sais si je suis assez clair?
C'est la seule méthode que j'ai réussit à faire marcher à peu près.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6220
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [MY-AL]Rotation dans une boule

Message par boubouk50 » 23 Jan 2019 11:56

D'accord donc tu veux faire un drag de la sphere, c'est à dire faire une rotation en fonction du curseur.
Hum, là, comme ça, je sèche, il me faudrait expérimenter.

Lors du Drag, tu pourrais faire un Raycast pour savoir où tu touches la sphère, comparer cette position avec la précédente (hit du Raycast précédent), déterminer l'angle effectué par rapport au centre de la sphère et appliquer ensuite la rotation déterminée.
Je tenterai de ce côté là pour ma part.
Sinon, peut-être est-ce bien plus simple de déterminer 2 angles (X et Y) en fonction du delta de translation de la souris et de les appliquer sur la sphère, mais je ne sais pas si c'est simple que cela et si ça marche (surtout pour les pôles)
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

EmileF
Messages : 676
Inscription : 18 Mars 2017 19:39

Re: [MY-AL]Rotation dans une boule

Message par EmileF » 23 Jan 2019 12:19

Merci pour ta réponse.

Je maîtrise mal le RayCast. Si tu avais un petit exemple j'essayerai de l'appliquer pour voir. C'est vrai que je pense que ce serai mieux que ma solution que je vais exposer en suivant.

Devant ma caméra, j'ai disposé 9 colliders pour réceptionner les actions de la souris.
Chaque quad a un script nommé Touch :
Par rapport à sa position, les valeurs X_to... et Y_to... sont modifiées pour appliquer une rotation différente.

Code : Tout sélectionner

public class Touch : MonoBehaviour
{
    [Tooltip("Le script qui récupère les commandes")]
    public DragRot Maitre;
    [Tooltip("Transfert du MousePosition.x vers une rotation.x")]
    public int X_to_X;
    [Tooltip("Transfert du MousePosition.x vers une rotation.y")]
    public int X_to_Y;
    [Tooltip("Transfert du MousePosition.x vers une rotation.z")]
    public int X_to_Z;
    [Tooltip("Transfert du MousePosition.y vers une rotation.x")]
    public int Y_to_X;
    [Tooltip("Transfert du MousePosition.y vers une rotation.y")]
    public int Y_to_Y;
    [Tooltip("Transfert du MousePosition.y vers une rotation.z")]
    public int Y_to_Z;
    bool drag;
    int InverseY;

    private void OnMouseDown()
    {
        if (Maitre.methode == DragRot.Methode.Manivelle) Maitre.drag = true;
        if (Maitre.methode == DragRot.Methode.Yoyo) drag = true;
    }

    private void OnMouseOver()
    {
        if (Maitre.drag)
        {
            float axex = Input.GetAxis("Mouse X") * X_to_X;
            float axey = Input.GetAxis("Mouse X") * X_to_Y;
            float axez = Input.GetAxis("Mouse X") * X_to_Z;
            axex += Input.GetAxis("Mouse Y") * Y_to_X * InverseY;
            axey += Input.GetAxis("Mouse Y") * Y_to_Y * InverseY;
            axez += Input.GetAxis("Mouse Y") * Y_to_Z * InverseY;
            if (Maitre)
                Maitre.Rotate(axex, axey, axez);
        }
    }
    private void OnMouseDrag()
    {
        if (drag)
        {
            float axex = Input.GetAxis("Mouse X") * X_to_X;
            float axey = Input.GetAxis("Mouse X") * X_to_Y;
            float axez = Input.GetAxis("Mouse X") * X_to_Z;
            axex += Input.GetAxis("Mouse Y") * Y_to_X * InverseY;
            axey += Input.GetAxis("Mouse Y") * Y_to_Y * InverseY;
            axez += Input.GetAxis("Mouse Y") * Y_to_Z * InverseY;
            if (Maitre)
                Maitre.Rotate(axex, axey, axez);
        }
    }

    private void OnMouseUp()
    {
        if (Maitre.drag)
        {
            if (Maitre)
                Maitre.Termine();
            Maitre.drag = false;
        }
        if (drag)
        {
            if (Maitre)
                Maitre.Termine();
            drag = false;
        }
    }

    private void Update()
    {
        //inverse la rotation verticale si le maitre tourne le dos
        if (Maitre.transform.eulerAngles.y > 90 && Maitre.transform.eulerAngles.y < 270)
            InverseY = -1;
        else
            InverseY = 1;

    }
}

Ces commandes "Touchs" sont récupérées dans un script "DragRot" que voilà:

Code : Tout sélectionner

public class DragRot : MonoBehaviour
{
    public enum Methode
    {
        Yoyo,
        Manivelle
    }

    [Tooltip("Les objets à pivoter. C'est l'objet[0] qui sert de référence")]
    public Transform[] objets;
    [Tooltip("La méthode de drag. Yoyo : comme tirer sur la ficelle d'un yoyo")]
    public Methode methode;
    [Tooltip("Espace local ou mondial")]
    public Space Space;
    [Tooltip("Vitesse de rotation selon l'axe")]
    public Vector3 Speed; 
    [Tooltip("Rotation finale maxi (0 si pas de controle Maxi et mini")]
    public Vector3 maxi;
    [Tooltip("Rotation finale mini (Maxi à 0 si pas de controle Maxi et mini")]
    public Vector3 mini;
    [Tooltip("Pas à adopter pour la rotation finale")]
    public Vector3 Pas;

    Vector3 dest;
    bool move;
    internal bool drag;

    /// <summary>
    /// Applique la rotation appelé par une commande Touch
    /// </summary>
    /// <param name="x">rotation axe x</param>
    /// <param name="y">rotation axe y</param>
    /// <param name="z">rotation axe z</param>
    public void Rotate(float x, float y, float z)
    {
        Vector3 dir = new Vector3
        {
            y = x * Speed.x,
            x = y * Speed.y,
            z = z * Speed.z
        };

        for (int i = 0; i < objets.Length; i++)
        {
            dir = dir.normalized;
            objets[i].Rotate(Vector3.up, dir.y , Space);
            objets[i].Rotate(Vector3.right, dir.x, Space);
            objets[i].Rotate(Vector3.forward, dir.z, Space);
        }
    }

    /// <summary>
    /// Termine la rotation des objets quand le bouton de la souris est relaché
    /// </summary>
    public void Termine()
    {
        //La rotation finale
        dest = objets[0].eulerAngles;
        if (Space == Space.Self)
            dest = objets[0].localEulerAngles;

        //Si un pas est spécifié corrige la rotation finale en fonction du pas
        if (Pas != Vector3.zero)
        {
            dest = new Vector3(Mathf.Round(dest.x / Pas.x) * Pas.x,
                               Mathf.Round(dest.y / Pas.y) * Pas.y,
                               Mathf.Round(dest.z / Pas.z) * Pas.z);

            Vector3 dest2;
            dest2.x = this.dest.x + (this.dest.x > 0 ? Pas.x : -Pas.x);
            dest2.y = this.dest.y + (this.dest.y > 0 ? Pas.y : -Pas.y);
            dest2.z = this.dest.z + (this.dest.z > 0 ? Pas.z : -Pas.z);

            if (Vector3.Distance(dest2, dest) < Vector3.Distance(this.dest, dest))
                dest = dest2;
        }

        //Si maxi != zero limite la rotation finale au mini et maxi spécifié
        if (maxi != Vector3.zero)
        {
            dest.x = dest.x > maxi.x ? maxi.x : dest.x;
            dest.y = dest.y > maxi.y ? maxi.y : dest.y;
            dest.z = dest.z > maxi.z ? maxi.z : dest.z;
            dest.x = dest.x < mini.x ? mini.x : dest.x;
            dest.y = dest.y < mini.y ? mini.y : dest.y;
            dest.z = dest.z < mini.z ? mini.z : dest.z;
        }

        move = true;

    }

    private void Update()
    {
        //si move: termine la rotation en direction de la rotation finale
        if (move)
        {
            Vector3 rot = objets[0].eulerAngles;
            if (Space == Space.Self)
                rot = objets[0].localEulerAngles;

            Vector3 dif = new Vector3();
            if (Vector3.Distance(dest, rot) > Vector3.Distance(Speed, Vector3.zero))
            {
                dif.x = (dest.x - rot.x) * Speed.x * Time.deltaTime;
                dif.y = (dest.y - rot.y) * Speed.y * Time.deltaTime;
                dif.x = (dest.z - rot.z) * Speed.z * Time.deltaTime;
                AppliqueRot(dif);
            }
            else
            {
                move = false;
                dif = (dest - rot);
                AppliqueRot(dif);
            }
        }

    }

    /// <summary>
    /// Fait pivoter les objets
    /// </summary>
    /// <param name="dif">la différence de pivot à appliquer</param>
    private void AppliqueRot(Vector3 dif)
    {
        for (int i = 0; i < objets.Length; i++)
        {
            if (Space == Space.Self)
            {
                objets[i].localEulerAngles += dif;
            }
            else
            {
                objets[i].eulerAngles += dif;
            }

        }
    }

}

J'ai commenté mes scripts afin qu'il soient plus clairs.
Le script "DragRot" pourrait être plus simple, mais j'ai voulu lui apporter quelques options supplémentaires pour le rendre plus polyvalent.

Mes essais fonctionnent relativement bien. mais sûrement que ta méthode doit-être plus simple et surtout plus optimisée.
Voilà Qu'en penses-tu.

Tant que j'y suis, j'ai un autre problème, c'est avec les collisions.
Je ne sais pas comment filtrer les collisions.
Je voudrais que mon player n'entre pas en collision avec la sphère, mais que les autres objets eux, entrent en collision. Mais pour le moment, je n'ai pas encore fait mes recherches à ce sujet.

Merci.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
Sebela
Messages : 141
Inscription : 25 Juin 2014 21:39

Re: [MY-AL]Rotation dans une boule

Message par Sebela » 23 Jan 2019 14:46

Salut Emile,

Perso je fais un peu pareil sur mon projet, mais depuis l'extérieur de la boule qui est une planète (mon projet)

Voici ma méthode :
Dans mon update :

Code : Tout sélectionner

        transform.RotateAround(transform.position, _cam.transform.up, -_rotSpeedX * _rotSpeedMultiplier);
        transform.RotateAround(transform.position, _cam.transform.right, _rotSpeedY * _rotSpeedMultiplier);
        _rotSpeedX = Mathf.Lerp(_rotSpeedX, 0, .05f);
        _rotSpeedY = Mathf.Lerp(_rotSpeedY, 0, .05f);
Puis j'utilise OnMouseDrag :

Code : Tout sélectionner

    protected virtual void OnMouseDrag()
    {
        RotateObjet();
    }
    
        public void RotateObjet()
    {
        _rotSpeedX = Input.GetAxis("Mouse X");
        _rotSpeedY = Input.GetAxis("Mouse Y");
    }
    
    
Et ça marche quelque soit l'orientation de la sphere :)

EmileF
Messages : 676
Inscription : 18 Mars 2017 19:39

Re: [MY-AL]Rotation dans une boule

Message par EmileF » 23 Jan 2019 15:33

Grand merci Sebela

Formidable, 6 lignes de codes contre 2 scripts interminables, et ça marche très bien.
Il ne me reste plus qu'à l'étudier pour bien le comprendre.
Pour le faire fonctionner à partir de l'intérieur de la sphère, il suffit d'inverser le signe des _rotSpeed.

Encore un grand merci.

Je me suis penché sur la façon de filtrer les collisions, ça se passe au niveau des layers et dans le menu Edit/Project Settings/Physics en cas de besoin pour quelqu'un.
https://docs.unity3d.com/Manual/LayerBa ... ision.html

Edit :
J'ai regardé les explications chez unity de RotateAround Ce n'est pas très clair, surtout la traduction en français.
Mais grâce à Sebela, je crois avoir compris :
le premier paramètre c'est le point pivot, ça permet de faire des orbites,
le deuxieme parametre c'est l'axe de rotation vertical, horizontal ou autre,
et le troisième c'est la valeur de la rotation

Code : Tout sélectionner

transform.RotateAround(pivot, axe, angle de rotation);
Si ça peut aider...

Mais appliquer une rotation par rapport à l'axe de rotation d'un autre objet, je n'y aurai jamais pensé.
Utiliser l'orientation de la caméra pour calculer la rotation de l'objet, c'est tout simplement génial.
merci Sebela.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
Sebela
Messages : 141
Inscription : 25 Juin 2014 21:39

Re: [MY-AL]Rotation dans une boule

Message par Sebela » 23 Jan 2019 16:31

Mais de rien :D
Je me souviens m'être arraché les cheveux comme toi avant d'avoir trouvé cette fonction ;-)
Tous unis contre la maltraitance capillaire !

EmileF
Messages : 676
Inscription : 18 Mars 2017 19:39

Re: [MY-AL]Rotation dans une boule

Message par EmileF » 23 Jan 2019 17:54

Port du casque obligatoire pour éviter tout accident.
Merci encore.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Répondre

Revenir vers « (C#) CSharp »