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…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LPUpdate : MonoBehaviour {
[SerializeField] private ReflectionProbe _waterReflectionProbe;
[SerializeField] private int _wRPRenderID = -1;
[SerializeField] private Camera _cam;
private Plane[] _planes;
// Start is called before the first frame update
void Start () {
this._waterReflectionProbe = this.GetComponent<ReflectionProbe> ();
this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
}
// Update is called once per frame
void Update () {
// Verifica se o Reflection probe está dentro do campo de visão da camera
if (GeometryUtility.TestPlanesAABB (this._planes, this._waterReflectionProbe.bounds)) {
RefreshReflProbe (true);
} else {
RefreshReflProbe (false);
}
}
IEnumerator RefreshReflProbe (bool shouldRefresh) {
while (shouldRefresh) {
yield return new WaitForSeconds (0.15f);
this._wRPRenderID = this._waterReflectionProbe.RenderProbe ();
}
}
}
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…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LPUpdate : MonoBehaviour {
[SerializeField] private ReflectionProbe _waterReflectionProbe;
[SerializeField] private int _wRPRenderID = -1;
[SerializeField] private Camera _cam;
private Plane[] _planes;
private IEnumerator _refreshRP;
// Start is called before the first frame update
void Start () {
this._waterReflectionProbe = this.GetComponent<ReflectionProbe> ();
this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
}
// Update is called once per frame
void Update () {
// Verifica se o Reflection probe está dentro do campo de visão da camera
if (GeometryUtility.TestPlanesAABB (this._planes, this._waterReflectionProbe.bounds)) {
Debug.Log ("ReflectionProbe inside the camera field of view");
if (this._refreshRP != null)
StopCoroutine (this._refreshRP);
this._refreshRP = RefreshReflProbe (true);
StartCoroutine (this._refreshRP);
} else {
Debug.Log ("ReflectionProbe outside the camera field of view");
if (this._refreshRP != null)
StopCoroutine (this._refreshRP);
this._refreshRP = RefreshReflProbe (false);
StopCoroutine (this._refreshRP);
}
}
IEnumerator RefreshReflProbe (bool shouldRefresh) {
while (shouldRefresh) {
yield return new WaitForSeconds (0.15f);
this._wRPRenderID = this._waterReflectionProbe.RenderProbe ();
}
}
}
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.
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:
ReflectionProbe inside the camera field of view.
Bounds: Center: (605.0, 6.1, 812.9), Extents: (9.0, 7.5, 9.0)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LPUpdate : MonoBehaviour {
[SerializeField] private ReflectionProbe _waterReflectionProbe;
[SerializeField] private BoxCollider _waterReflectionProbeColl;
[SerializeField] private int _wRPRenderID = -1;
[SerializeField] private Camera _cam;
private Plane[] _planes;
private IEnumerator _refreshRP;
private bool _coroutineRunning = false;
[SerializeField] private float _waitTimeToRefreshReflProbe = 0.15f;
// Start is called before the first frame update
void Start () {
this._waterReflectionProbe = this.GetComponent<ReflectionProbe> ();
this._waterReflectionProbeColl = GetComponent<BoxCollider> ();
this._waterReflectionProbeColl.size = this._waterReflectionProbe.size;
this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
this._refreshRP = RefreshReflProbe2 ();
}
// Update is called once per frame
void Update () {
// Verifica se o Reflection probe está dentro do campo de visão da camera
if (GeometryUtility.TestPlanesAABB (this._planes, this._waterReflectionProbeColl.bounds)) {
Debug.Log ("ReflectionProbe inside the camera field of view.\nBounds: " + this._waterReflectionProbeColl.bounds);
if (!this._coroutineRunning && this._refreshRP != null)
StartCoroutine (this._refreshRP);
} else {
Debug.Log ("ReflectionProbe outside the camera field of view");
if (this._coroutineRunning && this._refreshRP != null) {
StopCoroutine (this._refreshRP);
this._coroutineRunning = false;
}
}
}
IEnumerator RefreshReflProbe2 () {
while (true) {
this._coroutineRunning = true;
yield return new WaitForSeconds (this._waitTimeToRefreshReflProbe);
this._wRPRenderID = this._waterReflectionProbe.RenderProbe ();
}
}
}
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…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class logBounds : MonoBehaviour {
[SerializeField] private Camera _cam;
private Plane[] _planes;
// Start is called before the first frame update
void Start () {
this._planes = GeometryUtility.CalculateFrustumPlanes (this._cam);
}
// Update is called once per frame
void Update () {
Debug.Log ("Cube bounds: " + this.transform.GetComponent<BoxCollider> ().bounds);
if (GeometryUtility.TestPlanesAABB (this._planes, this.transform.GetComponent<BoxCollider> ().bounds)) {
Debug.Log ("The cube is inside the camera field of view.");
} else {
Debug.Log ("The cube is outside the camera field of view.");
}
}
}
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
private static Plane FromVec4(Vector4 aVec)
{
Vector3 n = aVec;
float l = n.magnitude;
return new Plane(n / l, aVec.w/l);
}
public static void UpdatePlanes(Plane[] planes, Matrix4x4 m)
{
if (planes == null || planes.Length < 6)
return;
var r0 = m.GetRow(0);
var r1 = m.GetRow(1);
var r2 = m.GetRow(2);
var r3 = m.GetRow(3);
planes[0] = FromVec4(r3 + r0); // Left
planes[1] = FromVec4(r3 - r0); // Right
planes[2] = FromVec4(r3 + r1); // Bottom
planes[3] = FromVec4(r3 - r1); // Top
planes[4] = FromVec4(r3 + r2); // Near
planes[5] = FromVec4(r3 - r2); // Far
}
public static void UpdatePlanes(Plane[] planes, Camera cam)
{
UpdatePlanes(planes, cam.projectionMatrix * cam.worldToCameraMatrix);
}
This allows to update the 6 frustum planes without any garbage allocations as long as you reuse your planes array.