Page 1 sur 2

[DB][RESOLU] Bug translation de caméra saccadée (RaycastHit)

Publié : 29 Oct 2020 23:20
par Slyback
Bonjour,

Premier post sur ce forum. J'apprends à développer sur Unity en C# en autodidacte depuis peu, et je suis confronté à un problème que je n'arrive pas à résoudre. Le script est assez basique, mais je ne comprends ce qu'il se produit dans Unity pour amener à ce résultat (voir vidéo).
Je cherche à déplacer la caméra à la façon d'un "cliqué déplacé", en calculant le mouvement depuis les coordonnées issues du RaycastHit sur le terrain.
Malheureusement ça ne fonctionne pas car cela entraine des mouvements saccadés de la caméra. Il n'y a pas de contrainte appliquée à la caméra, qui est libre et sans parent.

https://youtu.be/cyrrpI78gqQ

Est-ce que vous voyez d'où le problème peut venir ?

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    Vector3 worldPositionStart;
    Vector3 worldPosition;
    Vector3 worldDirection;

    void Start ()
    {
        // Rigidbody camRigidbody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        // Obtenir la position initiale de la cible dans l'espace
        if (Input.GetMouseButtonDown(0))
        { 
            Ray rayStart  = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitDataStart;
            Debug.Log("Clic gauche");

            if (Physics.Raycast(rayStart, out hitDataStart))
            {
                worldPositionStart = hitDataStart.point;
            }
        }

        // Obtenir la direction du mouvement dans l'espace
        if (Input.GetMouseButton(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitData;

            if (Physics.Raycast(ray, out hitData))
            {
                worldPosition = hitData.point;
            }
            worldDirection = worldPositionStart - worldPosition;
        }

        // Translation de la caméra
        this.transform.position = new Vector3(worldDirection.x, this.transform.position.y, worldDirection.z);
        Debug.Log(this.transform.position);
    }
}
Merci,

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 02:22
par jmhoubre
Bonsoir,
tu devrais regarder la documentation de LateUpdate ().

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 07:42
par Slyback
Merci.

J'ai mis la translation de la caméra dans la boucle LateUpdate () mais j'ai toujours le même problème.
J'ai également fait un test avec un plan simple (pour voir si cela venait des hex tiles), même problème.

Cela vient donc du script en lui-même. Quelque chose n'est pas bon ou ne fonctionne pas comme attendu :gene:

Les valeurs en X et Z alternent à chaque frame.

edit: l'erreur vient de cette boucle car worldPosition a une valeur qui alterne à chaque frame, ce qui produit la saccade :

Code : Tout sélectionner

        if (Input.GetMouseButton(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitData;

            if (Physics.Raycast(ray, out hitData))
            {
                worldPosition = hitData.point;
            }
        }

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 10:15
par boubouk50
Je partirai sur le déplacement 2D (screenPosition) de la souris plutôt que la position World.
Vu que tu bouges ta caméra en même temps que la souris, le hitData.point n'est pas linéaire. Par exemple, si la caméra bouge plus vite que la souris, alors en allant vers la droite, le hitData.point suivant sera a gauche du précédent. Ainsi, ta caméra va aller a gauche, puis le suivant sera à droite (car la caméra aura bougé), il en résultera un effet "dans de scie".
Donc, au lieu de passer par le World Space, reste dans le Screen Space, et compare la position Screen de ta souris entre deux frames. Ainsi, le déplacement sera linéaire.

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 10:29
par jmhoubre
J'ai remplacé Input.GetMouseButton par Input.GetMouseButtonUp, et je n'ai plus le mouvement saccadé. Cela semble aller dans le sens de ce que t'indiques boubouk

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 11:04
par jmhoubre
En relisant ton code avec le commentaire de boubouk en tête, j'ai légèrement modifié ton code pour ajouter à la position de la souris le déplacement à faire, puis mettre à zéro le déplacement.

Code : Tout sélectionner

using UnityEngine;

public class CameraController : MonoBehaviour
{
	private Vector3 mousePositionStart;
	private Vector3 mousePositionEnd;
	private Vector3 mouvement;

	void Update ()
	{
		// Obtenir la position initiale de la cible.
		if (Input.GetMouseButtonDown (0))
		{
			Ray rayStart = Camera.main.ScreenPointToRay (Input.mousePosition);
			RaycastHit hitDataStart;

			if (Physics.Raycast (rayStart, out hitDataStart))
			{
				mousePositionStart = hitDataStart.point;
			}
		}

		// Obtenir la translation à effectuer.
		if (Input.GetMouseButtonUp (0))
		{
			Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
			RaycastHit hitData;

			if (Physics.Raycast (ray, out hitData))
			{
				mousePositionEnd = hitData.point;
			}

			mouvement = mousePositionEnd - mousePositionStart;
		}

	}

	private void LateUpdate ()
	{
		// Translation de la caméra.
		transform.position -= mouvement;
		mouvement = Vector3.zero;
	}
}

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 11:44
par Slyback
Merci pour vos réponses, je comprends mieux le problème maintenant.

J'avais réalisé un script précédent utilisant effectivement le déplacement de la souris à l'écran pour donner les mouvements de la caméra. Le problème est qu'il ne prenait pas en compte l'éloignement de la cible du clic dans l'espace, et cela se ressentait dans le cliqué-glissé.

Il faut donc que je trouve une formule pour calculer l'éloignement de la cible du clic à chaque frame de façon calculée et non mesurée, en sachant que l'angle de vue de la caméra en perspective est fixe (35°) et que sa rotation et altitude y sont fixes également.

Pour ta solution jmhoubre, le problème c'est que Input.GetMouseButtonUp() ne donne qu'une seule valeur, et une fois que l'utilisateur a relaché le bouton. Or, il faut que la translation se fasse en temps-réel de manière fluide, quand l'utilisateur a encore le doigt sur le bouton.

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 12:06
par boubouk50
Sinon, faire l'inverse.
A ton premier clic (down), tu récupères le point de Raycast.
Ensuite, tu fais en sorte que ce point reste sous la souris, donc un déplacement entre le point actuel et le point précédent.

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 14:03
par Slyback
Je n'ai pas compris ce que tu proposes dans ton dernier commentaire boubouk50, il me semblait avoir fait ça dans mon code.

Après un peu de maths, j'ai trouvé la formule qui permet de calculer la profondeur :
y étant la valeur de hauteur du curseur à l'écran (comprise entre 0 et 1)
z étant la profondeur de l'espace visible à l'écran
altitude étant la hauteur de la caméra dans la scène
FOV étant le Field of View de la caméra

z = altitude / ( tan ( FOV * ( 1,5 - y ) ) )
Ainsi, zmin correspondrait à (y = 0) et zmax à (y = 1).

Dans mon cas, zmin ~ 26.92 et zmax ~ 112,90.

Re: [DB] Bug translation de caméra saccadée (RaycastHit)

Publié : 30 Oct 2020 14:30
par boubouk50
Dans ton premier script, tu faisais une affectation de la position de la caméra depuis le vecteur défini par le premier point défini par ton premier raycast et la position actuelle défini par le raycast en cours. Du coup, comme la caméra bougeait, la translation était "polluée" par ce mouvement. En gros ton code pouvait fonctionner si le calcul se faisait avec une caméra qui ne bougeait pas. (j'arrive pas trop à l'expliquer correctement désolé, disons que le mouvement de la caméra annule un peu la nouvelle position)
Je te propose, de déplacer la caméra via un Translate du vecteur entre la position en cours et la précédente pour calculer le delta qu'a fait ta souris en World Space, et donc éviter cette "pollution".
Ca rejoint ce que jmhoubre a fait dans son script avec le += sur la position.