[MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

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
Wadison
Messages : 19
Inscription : 23 Sep 2017 22:31

[MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par Wadison » 03 Oct 2017 22:56

J'ai codé naïvement avec un rayon, pour avoir aucun obstacle entre le personnage et la camera.
=> un rayon est lancé du personnage vers la camera, si il n'arrive pas jusqu'à la camera alors j'ajuste la position au point d'impact.
au repos la camera retourne à sa position précédente (gérer dans une classe).

Ca fonctionne mais je me prend quelques fois des sursauts désagréables.
Autre limite, la camera est trop bien ajusté et donc la "face" en collision est non visible à l'écran -gênant pour le sol.

Je voulais connaître les principes/stratégies pour améliorer l'ordinaire au tour de cette problématique.

je peux lancer un rayon dans l'autre sens pour connaître l'épaisseur et savoir si la camera est derrière ou dans un volume. C'est une bonne idée à creuser? Tester des idées est chronophage quelques conseils ne font pas de mal. Il faut alterner les plaisirs :)
Le lancé d'un rayon est une opération couteuse??

https://www.youtube.com/watch?v=Nu7rc4lUsF0

Code : Tout sélectionner

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

public class ShowEveryTime : MonoBehaviour
{

    public GameObject target; 
    
    public void LateUpdate()
    {

        var targetpos = target.transform.position;
        targetpos.y += 4;

        Ray ray = new Ray(targetpos, this.transform.position - targetpos);
        var max = (targetpos - this.transform.position).magnitude;

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit,max))
        {
            if(hit.distance < max)
            {
                this.transform.position = hit.point;
                Debug.DrawLine(targetpos, hit.point, Color.red);
            }
            else
            {
                Debug.DrawLine(targetpos, hit.point, Color.gray);
            }            
        }

        transform.LookAt(target.transform);
    }
}

yonathgames
Messages : 45
Inscription : 18 Sep 2017 17:44

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par yonathgames » 05 Oct 2017 17:46

C'est déjà pas mal du tout!!! :super:

Je pense que tu peux améliorer ( éviter les sursauts) en ajustant la position de la caméra avec un Lerp.
Ensuite, pour éviter que la caméra soit contre la paroi et que celle-ci ne soit pas visible, il faudrait implémenter un décalage.

Wadison
Messages : 19
Inscription : 23 Sep 2017 22:31

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par Wadison » 05 Oct 2017 22:51

Hello,

Du coup j'ai tenté, ce que tu suggères.
Et Je suis bien content d'avoir trouvé directement disponible "RaycastHit.normal" pour ajouter marge orthogonale à la face.
l'API unity3D est vraiment agréable à utiliser!

Pour la mise en place d'un traveling (Lerp), j'ai tenté a contre cœur. Ceci évite le sursaut en effet, mais du coup la camera traverse les murs - je vais m'en satisfaire. Mais il faut que je travaille l'anim qui rétabli la camera au repos.

RQ - Si quelqu'un reprend le script il faut comprendre que j'ai un second script exécuté avant qui réinitialise la camera à sa position sans correction.

Code : Tout sélectionner

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

public class ShowEveryTime : MonoBehaviour
{

    public GameObject target;
    private float speedAdjustement = 4f;
    private float margin = 0.2f;

    private float time = 0;

    public void LateUpdate()
    {

        var targetpos = target.transform.position;
        var campos = this.transform.position;

        Ray ray = new Ray(targetpos, campos  - targetpos);
        var max = (targetpos - campos ).magnitude;

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, max))
        {
            if(hit.distance < max)
            {
                var tweakTarget = hit.point + hit.normal* margin;
                var gap = tweakTarget - campos;
                
                time += Time.deltaTime;
                this.transform.position = Vector3.Lerp(campos, tweakTarget, time * speedAdjustement);

                Debug.DrawLine(this.transform.position, hit.point, Color.red);
                Debug.DrawLine(hit.point, tweakTarget, Color.green);
            }          
        }
        else
        {
            time = 0;
        }

        transform.LookAt(target.transform);
    }
}

yonathgames
Messages : 45
Inscription : 18 Sep 2017 17:44

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par yonathgames » 05 Oct 2017 23:42

Pour la traversée des murs, pourquoi ne pas tirer un raycast en avant de la camera horizontalement et la faire monter graduellement lorsqu'elle rencontre un mur? :idea:

Wadison
Messages : 19
Inscription : 23 Sep 2017 22:31

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par Wadison » 09 Oct 2017 23:14

J'ai essayé plein de truc, dont ta dernière idée.

Et finalement la synthèse, est l'utilisation de 4 rayons lancés vers les 4 bords de l'écran :
https://youtu.be/hjwBOlQbuDc

il reste quelques mystères. Il faudrait trouver des ressources qui parle du sujet.

Code : Tout sélectionner

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

public class ShowEveryTimeCorners : MonoBehaviour
{

    public GameObject target;
    //private float margin = 0.2f;
    private float zoom = 1f;
    private float angle = 0.2f; 


    struct RayCastResult
    {
        public RaycastHit hit;
        public bool hitted;
    }

    RayCastResult RayCastFromTo(Vector3 source, Vector3 destination) { 
        
        var orientation = destination - source;
        var ret = new RayCastResult();
        var ray = new Ray(source, orientation);
        var marginvector = Vector3.zero;
        ret.hitted = Physics.Raycast(ray, out ret.hit, orientation.magnitude,1);
        if(ret.hitted)
            Debug.DrawLine(source, ret.hit.point, Color.red);

        else
            Debug.DrawLine(source, source + orientation, Color.gray);

        return ret;
    }
     
    public void LateUpdate()
    {
        var targetpos = target.transform.position;
        var campos = this.transform.position;
        var orientation = campos - targetpos;
        var zoomedcampos = targetpos + orientation * zoom;
        
         
         
        {
            var corners = new[] {
                this.transform.TransformPoint(0, -angle, 0),  // bottom
                this.transform.TransformPoint(angle, 0, 0),   // right
                this.transform.TransformPoint(-angle, 0, 0),  //left
                this.transform.TransformPoint(0, angle, 0)    //top
            };
            
            var min = float.MaxValue;
            foreach (var t in corners)
            {
                var r =RayCastFromTo(targetpos, t);
                if (r.hitted) min = Mathf.Min(min, r.hit.distance);
            }

            if(min < float.MaxValue)
            {
                var targetzoom = min / orientation.magnitude;
                zoom = targetzoom; 
            }
            else
            {
              ZoomOut(Time.deltaTime);
            }
             
        }
         

        ApplyZoom(targetpos, orientation); 

        transform.LookAt(target.transform);
    }

    private void ApplyZoom(Vector3 targetpos, Vector3 orientation)
    {
        this.transform.position = targetpos + orientation * zoom;
    }

    private void ZoomIn(float delta)
    {
        zoom = Mathf.Max(zoom - delta, 0);
    }
     
    private void ZoomOut(float delta)
    {
        zoom = Mathf.Min(zoom + delta, 1);
    }
}



yonathgames
Messages : 45
Inscription : 18 Sep 2017 17:44

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par yonathgames » 10 Oct 2017 08:50

Ta caméra passe trop prêt de ton personnage, c'est pour cela qu'il disparait. Tu peux régler la profondeur de visualisation mais il est possible que l'on ai un effet bof avec une vision du personnage en très gros plan :|

Je pense que tu tiens le bon bout!

Wadison
Messages : 19
Inscription : 23 Sep 2017 22:31

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par Wadison » 10 Oct 2017 09:46

Je voulais en parler dans un autre post, En fait je n'arrive pas à faire un fondu.
Alors j'ai simplement disable l'objet.

Mais je suis tombé la dessus, https://docs.unity3d.com/Manual/Standar ... gMode.html
je n'ai encore vu dans UI.
 ! Message de : boubouk50
Salut Wadison, il est préférable de créer un nouveau post pour parler de ce second problème. Un post par problème pour ne pas mélanger les informations et les résolutions. Comme le fondu est lié à ce post-ci, tu peux laisser un lien vers le nouveau post sur le fondu par exemple.

yonathgames
Messages : 45
Inscription : 18 Sep 2017 17:44

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par yonathgames » 10 Oct 2017 11:38

A mon avis tu te lances dans un truc compliqué... Je n'ai pas étudié ton script mais il doit y avoir un moyen de créer un décalage vers le haut lorsque la caméra est très proche du personnage.
En plus, tes fades seront très rapides. je ne suis pas sûr que ce soit visuellement intéressant.

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

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par boubouk50 » 10 Oct 2017 12:55

yonathgames a écrit :
10 Oct 2017 11:38
Je n'ai pas étudié ton script mais il doit y avoir un moyen de créer un décalage vers le haut lorsque la caméra est très proche du personnage.
Genre un simple sphereCollider spécial caméra qui a un rayon supérieur au Near Clip?
"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

Wadison
Messages : 19
Inscription : 23 Sep 2017 22:31

Re: [MY-AL] Camera qui ne passe pas à travers les murs- Amélioration?

Message par Wadison » 10 Oct 2017 22:10

En fait, j'ai fait des modifications mineurs, je lance les rayons du coin des écrans ( à la louche), Et les origines des rayons sont décalées dans un plan hortogonal à celui de la camera (var source = targetpos + (t - this.transform.position)). C'est peut être plus parlant sur la vidéo.
https://youtu.be/XqWL00SlZqc

Depuis que j'ai ajouté fade In/out je trouve les sursauts provoqués par les murets beaucoup moins violent visuellement! Je suis enfin enthousiaste du résultat. J'ai quand même deux trois réglages à faire dessus mais j'en parle dans un autre post :p (ici viewtopic.php?f=8&t=14801&p=107422#p107422)

Dernière version du code :

Code : Tout sélectionner

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

public class ShowEveryTimeCorners : MonoBehaviour
{

    public GameObject target;
    private float zoom = 1f;
    private float angle = 0.2f; 


    struct RayCastResult
    {
        public RaycastHit hit;
        public bool hitted;
    }

    RayCastResult RayCastFromTo(Vector3 source, Vector3 destination) { 
        
        var orientation = destination - source;
        var ret = new RayCastResult();
        var ray = new Ray(source, orientation);
        var marginvector = Vector3.zero;
        ret.hitted = Physics.Raycast(ray, out ret.hit, orientation.magnitude,1);
        if(ret.hitted)
            Debug.DrawLine(source, ret.hit.point, Color.red);

        else
            Debug.DrawLine(source, source + orientation, Color.gray);

        return ret;
    }
     
    public void LateUpdate()
    {
        var targetpos = target.transform.position;
        var campos = this.transform.position;
        var orientation = campos - targetpos;
        var zoomedcampos = targetpos + orientation * zoom;
        
         
         
        {
            var corners = new[] {
                this.transform.TransformPoint(angle, -angle, 0),  // right bottom
                this.transform.TransformPoint(angle,angle, 0),   // right top
                this.transform.TransformPoint(-angle,-angle, 0),  //left bottom
                this.transform.TransformPoint(-angle, angle, 0)    //left top
            };
            
            var min = float.MaxValue;
            foreach (var t in corners)
            {
                var source = targetpos + (t - this.transform.position);
                var r =RayCastFromTo(source, t);
                if (r.hitted) min = Mathf.Min(min, r.hit.distance);
            }

            if(min < float.MaxValue)
            {
                var targetzoom = min / orientation.magnitude;
                zoom = targetzoom; 
            }
            else
            {
              ZoomOut(Time.deltaTime);
            }
             
        }

        ApplyZoom(targetpos, orientation); 
        transform.LookAt(target.transform);
    }

    private void ApplyZoom(Vector3 targetpos, Vector3 orientation)
    {
        this.transform.position = targetpos + orientation * zoom;
    }

    private void ZoomIn(float delta)
    {
        zoom = Mathf.Max(zoom - delta, 0);
    }
     
    private void ZoomOut(float delta)
    {
        zoom = Mathf.Min(zoom + delta, 1);
    }
}
Dernière édition par Wadison le 10 Oct 2017 22:48, édité 1 fois.

Répondre

Revenir vers « (C#) CSharp »