Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Resolved How to detect if a ReflectionProbe is inside camera frustum with TestPlanesAABB() ?

Discussion in 'Scripting' started by Victoralm, Aug 14, 2020.

  1. Victoralm

    Victoralm

    Joined:
    Dec 31, 2015
    Posts:
    30
    Hi,

    I'm trying to detect if a ReflectionProbe is inside camera frustum using TestPlanesAABB(). But 'till now, without success...

    I put the following script on the ReflectionProbe itself and dragged the appropriate camera to its field. But not working...

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class LPUpdate : MonoBehaviour {
    6.  
    7.     [SerializeField] private ReflectionProbe _waterReflectionProbe;
    8.     [SerializeField] private int _wRPRenderID = -1;
    9.  
    10.     [SerializeField] private Camera _cam;
    11.     private Plane[] _planes;
    12.  
    13.     // Start is called before the first frame update
    14.     void Start () {
    15.         this._waterReflectionProbe = this.GetComponent<ReflectionProbe> ();
    16.         this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update () {
    21.  
    22.         // Verifica se o Reflection probe está dentro do campo de visão da camera
    23.         if (GeometryUtility.TestPlanesAABB (this._planes, this._waterReflectionProbe.bounds)) {
    24.             RefreshReflProbe (true);
    25.         } else {
    26.             RefreshReflProbe (false);
    27.         }
    28.     }
    29.  
    30.     IEnumerator RefreshReflProbe (bool shouldRefresh) {
    31.         while (shouldRefresh) {
    32.             yield return new WaitForSeconds (0.15f);
    33.             this._wRPRenderID = this._waterReflectionProbe.RenderProbe ();
    34.         }
    35.     }
    36. }
    Need some help, please.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,780
    That sure seems like you're doing it right.

    I recommend using Debug.Log to print out the bounds values, see whether they are reasonable compared to the camera frustum.

    You can also just construct a bounds that you KNOW is in the frustum planes and check.
     
  3. Victoralm

    Victoralm

    Joined:
    Dec 31, 2015
    Posts:
    30
    Using Debug.Log looks like the ReflectionProbe is always inside the camera frustum, no matter if the camera is far away from the ReflectionProbe and looking to oposite direction. Also, it doesn't start my coroutine...
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class LPUpdate : MonoBehaviour {
    6.  
    7.     [SerializeField] private ReflectionProbe _waterReflectionProbe;
    8.     [SerializeField] private int _wRPRenderID = -1;
    9.  
    10.     [SerializeField] private Camera _cam;
    11.     private Plane[] _planes;
    12.  
    13.     private IEnumerator _refreshRP;
    14.  
    15.     // Start is called before the first frame update
    16.     void Start () {
    17.         this._waterReflectionProbe = this.GetComponent<ReflectionProbe> ();
    18.         this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
    19.     }
    20.  
    21.     // Update is called once per frame
    22.     void Update () {
    23.  
    24.         // Verifica se o Reflection probe está dentro do campo de visão da camera
    25.         if (GeometryUtility.TestPlanesAABB (this._planes, this._waterReflectionProbe.bounds)) {
    26.             Debug.Log ("ReflectionProbe inside the camera field of view");
    27.  
    28.             if (this._refreshRP != null)
    29.                 StopCoroutine (this._refreshRP);
    30.  
    31.             this._refreshRP = RefreshReflProbe (true);
    32.  
    33.             StartCoroutine (this._refreshRP);
    34.         } else {
    35.             Debug.Log ("ReflectionProbe outside the camera field of view");
    36.             if (this._refreshRP != null)
    37.                 StopCoroutine (this._refreshRP);
    38.  
    39.             this._refreshRP = RefreshReflProbe (false);
    40.  
    41.             StopCoroutine (this._refreshRP);
    42.         }
    43.     }
    44.  
    45.     IEnumerator RefreshReflProbe (bool shouldRefresh) {
    46.         while (shouldRefresh) {
    47.             yield return new WaitForSeconds (0.15f);
    48.             this._wRPRenderID = this._waterReflectionProbe.RenderProbe ();
    49.         }
    50.     }
    51. }
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,780
    I see four possible outcomes

    - the bounds is bigger than you think
    - the frustum is WAY bigger than you think
    - both bounds and frustum are bigger than you think
    - there's broken code in the TestPlanesAABB

    You alone are positioned the best to identify which of the four above things are happening... or maybe... maybe it's something ELSE!

    But I would highly advise from one engineer to another, eliminate the things we CAN imagine, then move onto more imaginary things if you actually need to.
     
  5. Victoralm

    Victoralm

    Joined:
    Dec 31, 2015
    Posts:
    30
    New attempt:
    Now I try with the bound of a collision box. Got the size of the collider (is trigger check) by the size of the "Box Size" of the ReflectionProbe component. The coroutine is starting now. But it never reaches the else of the GeometryUtility.TestPlanesAABB() test, no matters where the camera is or where its looking at...
    I think that, maybe, the bounds are strange. The Log return:
    Code (CSharp):
    1. ReflectionProbe inside the camera field of view.
    2. Bounds: Center: (605.0, 6.1, 812.9), Extents: (9.0, 7.5, 9.0)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class LPUpdate : MonoBehaviour {
    6.  
    7.     [SerializeField] private ReflectionProbe _waterReflectionProbe;
    8.     [SerializeField] private BoxCollider _waterReflectionProbeColl;
    9.     [SerializeField] private int _wRPRenderID = -1;
    10.  
    11.     [SerializeField] private Camera _cam;
    12.     private Plane[] _planes;
    13.  
    14.     private IEnumerator _refreshRP;
    15.     private bool _coroutineRunning = false;
    16.     [SerializeField] private float _waitTimeToRefreshReflProbe = 0.15f;
    17.  
    18.     // Start is called before the first frame update
    19.     void Start () {
    20.         this._waterReflectionProbe = this.GetComponent<ReflectionProbe> ();
    21.         this._waterReflectionProbeColl = GetComponent<BoxCollider> ();
    22.         this._waterReflectionProbeColl.size = this._waterReflectionProbe.size;
    23.         this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
    24.  
    25.         this._refreshRP = RefreshReflProbe2 ();
    26.  
    27.     }
    28.  
    29.     // Update is called once per frame
    30.     void Update () {
    31.  
    32.         // Verifica se o Reflection probe está dentro do campo de visão da camera
    33.         if (GeometryUtility.TestPlanesAABB (this._planes, this._waterReflectionProbeColl.bounds)) {
    34.  
    35.             Debug.Log ("ReflectionProbe inside the camera field of view.\nBounds: " + this._waterReflectionProbeColl.bounds);
    36.  
    37.             if (!this._coroutineRunning && this._refreshRP != null)
    38.                 StartCoroutine (this._refreshRP);
    39.  
    40.         } else {
    41.  
    42.             Debug.Log ("ReflectionProbe outside the camera field of view");
    43.  
    44.             if (this._coroutineRunning && this._refreshRP != null) {
    45.                 StopCoroutine (this._refreshRP);
    46.                 this._coroutineRunning = false;
    47.             }
    48.  
    49.         }
    50.     }
    51.  
    52.     IEnumerator RefreshReflProbe2 () {
    53.         while (true) {
    54.             this._coroutineRunning = true;
    55.             yield return new WaitForSeconds (this._waitTimeToRefreshReflProbe);
    56.             this._wRPRenderID = this._waterReflectionProbe.RenderProbe ();
    57.         }
    58.     }
    59. }
     
    Last edited: Aug 14, 2020
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    One thing's for sure, this one
    Code (CSharp):
    1.  this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
    needs to be called more often, at least when the camera changes (moves, rotates, field of view changed...),

    At the moment you only calculate the planes just once in Start. The planes won't change if you don't calculate them again, you need to update them.
     
    Bunny83, Kurt-Dekker and Victoralm like this.
  7. Victoralm

    Victoralm

    Joined:
    Dec 31, 2015
    Posts:
    30
    I think that must be something wrong... I try this with the default cube and the Debug.Log always returns the else of the test, even when I was in front of the cube...

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class logBounds : MonoBehaviour {
    6.  
    7.     [SerializeField] private Camera _cam;
    8.     private Plane[] _planes;
    9.  
    10.     // Start is called before the first frame update
    11.     void Start () {
    12.         this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
    13.  
    14.     }
    15.  
    16.     // Update is called once per frame
    17.     void Update () {
    18.         Debug.Log ("Cube bounds: " + this.transform.GetComponent<BoxCollider> ().bounds);
    19.         if (GeometryUtility.TestPlanesAABB (this._planes, this.transform.GetComponent<BoxCollider> ().bounds)) {
    20.             Debug.Log ("The cube is inside the camera field of view.");
    21.         } else {
    22.             Debug.Log ("The cube is outside the camera field of view.");
    23.         }
    24.     }
    25. }
     
    Last edited: Aug 14, 2020
  8. Victoralm

    Victoralm

    Joined:
    Dec 31, 2015
    Posts:
    30
    I put it in Update() and it did the trick!!
    Thanks a lot mate!!
     
    Suddoha likes this.
  9. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,539
    You might want to use my *manual* method to recalculate the frustum planes. I've posted it in a nested comment over here but I'll copy it over since UA becomes more and more unreliable

    Code (CSharp):
    1. private static Plane FromVec4(Vector4 aVec)
    2. {
    3.      Vector3 n = aVec;
    4.      float l = n.magnitude;
    5.      return new Plane(n / l, aVec.w/l);
    6. }
    7.  
    8. public static void UpdatePlanes(Plane[] planes, Matrix4x4 m)
    9. {
    10.      if (planes == null || planes.Length < 6)
    11.          return;
    12.      var r0 = m.GetRow(0);
    13.      var r1 = m.GetRow(1);
    14.      var r2 = m.GetRow(2);
    15.      var r3 = m.GetRow(3);
    16.    
    17.      planes[0] = FromVec4(r3 + r0); // Left
    18.      planes[1] = FromVec4(r3 - r0); // Right
    19.      planes[2] = FromVec4(r3 + r1); // Bottom
    20.      planes[3] = FromVec4(r3 - r1); // Top
    21.      planes[4] = FromVec4(r3 + r2); // Near
    22.      planes[5] = FromVec4(r3 - r2); // Far
    23. }
    24. public static void UpdatePlanes(Plane[] planes, Camera cam)
    25. {
    26.      UpdatePlanes(planes, cam.projectionMatrix * cam.worldToCameraMatrix);
    27. }
    This allows to update the 6 frustum planes without any garbage allocations as long as you reuse your planes array.
     
    Anarkila and Munchy2007 like this.