Search Unity

Collider Extension: how to work with .IsTargetObscured() and .CameraWasDisplaced() ?

Discussion in 'Cinemachine' started by Jean-Fabre, Apr 19, 2018.

  1. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi Guys,

    I am having trouble understanding how to work with both .IsTargetObscured() and .CameraWasDisplaced()

    It never returns true, even though obviously, the camera is displaced and or the target is obscured.

    I am using the scene Free Look collider, from the examples, and I have this component attached to the CM FreeLook1

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. using Cinemachine;
    6.  
    7. [RequireComponent(typeof(CinemachineCollider))]
    8. public class ColliderWatcher : MonoBehaviour {
    9.  
    10.     public bool IsTargetObscured;
    11.     public bool CameraWasDisplaced;
    12.  
    13.     CinemachineCollider _cache;
    14.  
    15.     public CinemachineVirtualCameraBase VirtualCamera;
    16.  
    17.     // Use this for initialization
    18.     void Start () {
    19.         _cache = this.GetComponent<CinemachineCollider> ();
    20.  
    21.     }
    22.    
    23.     // Update is called once per frame
    24.     void Update () {
    25.         if (_cache != null) {
    26.  
    27.             VirtualCamera = _cache.VirtualCamera;
    28.  
    29.             if (_cache.IsTargetObscured (_cache.VirtualCamera)) {
    30.                 Debug.Log ("IsTargetObscured");
    31.             }
    32.  
    33.             if (_cache.CameraWasDisplaced (_cache.VirtualCamera)) {
    34.                 Debug.Log ("CameraWasDisplaced");
    35.             }
    36.  
    37.  
    38.             IsTargetObscured = _cache.IsTargetObscured (_cache.VirtualCamera);
    39.             CameraWasDisplaced = _cache.CameraWasDisplaced (_cache.VirtualCamera);
    40.  
    41.         }
    42.     }
    43. }
    but IsTargetObscured and CameraWasDisplaced are never true. I disabled Avoid Obstacles in the collider to clearly get to a point where I can not see the target but IsTargetObscured is never set to true, and if I set it back to Avoid obstacle, the camera is clearly displaced, but CameraWasDisplacedis never true.

    What am I doing wrong here?

    Thanks,

    Jean
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    hmmm... it's working for me.
    Can you show me your collider inspector, and your vcam inspector, and the tags on your vcam's LookAt target?
    Also: what version of CM are you using?
     
  3. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    thanks for taking a look at this :)

    I am using
    - Unity 2017.1f3
    - Cinemachine latest ( 2.1.10)
    - the default example scene "Free Look collider" to which I add my ColliderWatcher which should log in the console everytime IsTargetObscured and CameraWasDisplaced are true and show it in the inspector as well.


    I made a small screencast to check that I am indeed getting nothing out of these, and that from what I am doing with the camera and player:

    https://imgur.com/Qm8Ielb

    It must be something very simple if you have no problem on your end, but it's odd that I get it straight from the example scene.

    Bye,

    Jean
     
  4. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    I am not too sure what you mean by vcam's lookat target tags... but I guess you have these infos from the scene, as I using the one provided without any modification. Right?

    Bye,

    Jean
     
  5. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Hi Jean,

    Sorry, but I was a little hasty answering your post... I had tried it with a normal vcam, not a FreeLook. In fact you are right, it's not working with the FreeLook.

    This is because the FreeLook is in fact a complex rig with 3 internal vcams. The API for IsTargetObscured and CameraWasDisplaced requires a vcam parameter. You have to pass the active child rig, not the parent. I've modified your script to do that, and it works now. Here is the modified script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Cinemachine;
    5.  
    6. [RequireComponent(typeof(CinemachineCollider))]
    7. public class ColliderWatcher : MonoBehaviour
    8. {
    9.     public bool IsTargetObscured;
    10.     public bool CameraWasDisplaced;
    11.  
    12.     CinemachineCollider _cache;
    13.  
    14.     // Use this for initialization
    15.     void Start()
    16.     {
    17.         _cache = this.GetComponent<CinemachineCollider>();
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void Update()
    22.     {
    23.         CinemachineVirtualCameraBase vcam = null;
    24.         if (_cache != null)
    25.             vcam = _cache.VirtualCamera.LiveChildOrSelf as CinemachineVirtualCameraBase;
    26.         if (vcam != null)
    27.         {
    28.             IsTargetObscured = _cache.IsTargetObscured(vcam);
    29.             CameraWasDisplaced = _cache.CameraWasDisplaced(vcam);
    30.         }
    31.     }
    32. }
    This will work with ordinary vcams too, as the LiveChildOrSelf method will just return self in that case.
     
  6. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Excellent! it works :)

    Thanks,

    Jean
     
  7. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    .LiveChildOrSelf is now out with the latest version of Cinemachine distributed via the Package Manager.

    how would that work now, what would be the right way to get the camera base?

    Bye,

    Jean
     
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    This should do the job:
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3. [RequireComponent(typeof(CinemachineCollider))]
    4. public class ColliderWatcher : MonoBehaviour
    5. {
    6.     public bool IsTargetObscured;
    7.     public bool CameraWasDisplaced;
    8.     CinemachineCollider _cache;
    9.     CinemachineVirtualCameraBase _middleRig;
    10.     // Use this for initialization
    11.     void Start()
    12.     {
    13.         _cache = this.GetComponent<CinemachineCollider>();
    14.         if (_cache != null)
    15.         {
    16.             var freeLook = _cache.VirtualCamera as CinemachineFreeLook;
    17.             if (freeLook != null)
    18.                 _middleRig = freeLook.GetRig(1);
    19.         }
    20.     }
    21.     // Update is called once per frame
    22.     void Update()
    23.     {
    24.         if (_middleRig != null)
    25.         {
    26.             IsTargetObscured = _cache.IsTargetObscured(_middleRig);
    27.             CameraWasDisplaced = _cache.CameraWasDisplaced(_middleRig);
    28.         }
    29.     }
    30. }
     
  9. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Thanks for the snippet :)

    If the rigs radius are exotic/oddly setup, would it not make sense to catch the current rig being used? the middle rig might not be used at the time of collision or displacement, no?


    Bye,

    Jean
     
  10. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Ok, I am going to just port the feature back. I really wonder why you got rid of it... doesn't make sense to me to remvoe this feature which seems not available in another form in the latest version of cinemachine.

    /// <summary>Returns the rig with the greatest weight</summary>
    public override ICinemachineCamera LiveChildOrSelf
    {
    get
    {
    // Do not update the rig cache here or there will be infinite loop at creation time
    if (m_Rigs == null || m_Rigs.Length != 3)
    return this;
    if (m_YAxis.Value < 0.33f)
    return m_Rigs[2];
    if (m_YAxis.Value > 0.66f)
    return m_Rigs[0];
    return m_Rigs[1];
    }
    }

    Bye,

    Jean
     
  11. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Sorry for the late reply (I'm travelling).
    You could re-implement, but my feeling is that in the case of the FreeLook it isn't necessary. LiveChildOrSelf is just an approximation, because the FreeLook is always in a blend state, and the middle rig is always part of the blend, even in extreme cases. Did you try with the code I gave? I think it will work.
     
  12. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Yeah, you are right. I think I'll leverage the new way so that I can make one package for all cinemachine versions.

    Thanks for your help :)

    Bye,

    Jean
     
    Gregoryl likes this.
  13. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Ok,

    one more thing. The problem with your snippet is that it assumes the virtualCamera is a CinemachineFreeLook, but really, I am making this as a generic system, so I can't implement that as is actually. so how can I get to the CameraBase with just a virtualCamera?

    Typically, I am working on a variant of the FreeLook Camera that has only one camera and not 3, as it's easier to setup for most case. Ideally, the component I am making should work for this variant too as it is meant to work with CinemachineCollider right?

    Bye,

    Jean

    ps: also struggling big time with 2018, visual studio is not seeing your package and doesn't see your namespace... trying to look for a solution on this as well :)
     
  14. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Code (CSharp):
    1.             if (freeLook != null)
    2.                 _middleRig = freeLook.GetRig(1);
    3.             else
    4.                 _middleRig = cache.VirtualCamera;
    PS Reinstalling VS might help.
     
  15. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    ok, I'll figure something out, because that doesn't scale well at all. Thanks for your time :)

    Bye,

    Jean
     
  16. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Why doesn't it scale well?
     
  17. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Because for every new component, I'll need an if statement. the LiveChildOrSelf was making a lot of sense to grow on that side of this type of components.

    Let me explain the context, maybe I am missing the obvious...

    I am porting Cinemachine to PlayMaker, and for this I need some proxy components or actions that the user can use to point to a ColliderExtension and get its infos like wether it's obscured or displaced.




    So, the problem is then that if I start putting if statements for every possible CinemachineVirtualCameraBase components, then I'll never be able to provide a stable solution over time that guarantee that when you have a pointer to a ColliderExtension you can query its status.

    I think LiveChildOrSelf was meant to account for this situation, and I am not sure what's the best replacement now that you removed that feature. If the new solution is to hardcode it, then that's an issue. Maybe there is a motivation behind removing this LiveChildOrSelf, but If it was purely because you though it was not used, then I'd like to raise a case where it would be good to have it back so that extensions are truly generic, which I think should be the case.

    again, I may miss the obvious, but the api is quite permeable :) I admit I am having a hard time with it and trying the understand the various concepts and approaches to make the most out of it and find the right points of entry to provide the best possible support for PlayMaker.

    Bye,

    Jean
     
  18. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    Thanks for the explanation. I see what you're saying and why you don't like the if. However, you only need it for the FreeLook - that's a very special case. In fact, that special case will almost certainly disappear in future releases, as CM evolves.

    The problem with LiveChildOrSelf is that it imposes the idea that there is necessarily a Live child. There isn't, and it becomes problematic to implement this in a meaningful way for vcams that have multiple Live children. MixingCamera is an example (and, actually, FreeLook is too, for the reasons I mentioned before). It's an inappropriate concept, and so it had to go.

    Actually I'm thinking that the child vcams are the private business of the FreeLook, and that the outside world should not need to know about them, so really the CM Collider API that takes the vcam child as a parameter is at fault. You should just be able to ask the vcam parent "Is the target obstructed?" and it should itself take care about querying the right children. Let me look into addressing this, but in the meantime you might have to hold your nose and make the special case :)
     
  19. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Yeah, you are right, I'll go with this :) Thanks for your help and patience.

    Bye,

    Jean