Skip to content

Commit a48c98f

Browse files
author
Julia Schwarz
committed
Remove FOV Cone check and fix edge case
- FOV Cone check breaks for large colliders whose corner is outside FOV cone - Fix edge case in existing code where colliders with corners in front and behind camera would be considered in FOV when they were not.
1 parent 4b9ac44 commit a48c98f

File tree

1 file changed

+32
-36
lines changed

1 file changed

+32
-36
lines changed

Assets/MixedRealityToolkit/Utilities/CameraFOVChecker.cs

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,15 @@ public static class CameraFOVChecker
2222
// List of corners shared across all sphere pointer query instances --
2323
// used to store list of corners for a bounds. Shared and static
2424
// to avoid allocating memory each frame
25-
private static List<Vector3> inFOVConeBoundsCornerPoints = new List<Vector3>();
25+
private static List<Vector3> inFOVBoundsCornerPoints = new List<Vector3>();
2626

2727
/// <summary>
2828
/// Returns true if a collider's bounds is within the camera FOV.
2929
/// Utilizes a cache to test if this collider has been seen before and returns current frame's calculated result.
30-
/// NOTE: This is a 'loose' FOV check -- it can return true in cases when the collider is actually not in the FOV
31-
/// because it does an axis-aligned check. So, if the axis aligned bounds are in the bounds of the camera, it will return true.
3230
/// </summary>
3331
/// <param name="myCollider">The collider to test</param>
34-
public static bool IsInFOVCached(this Camera cam,
35-
Collider myCollider, bool debug=false)
32+
public static bool IsInFOVCached(this Camera cam, Collider myCollider)
3633
{
37-
if(debug)
38-
{
39-
Debug.Log("debugging");
40-
}
4134
// if the collider's size is zero, it is not visible. Return false.
4235
if (myCollider.bounds.size == Vector3.zero || myCollider.transform.localScale == Vector3.zero)
4336
{
@@ -56,46 +49,49 @@ public static bool IsInFOVCached(this Camera cam,
5649
return result;
5750
}
5851

59-
inFOVConeBoundsCornerPoints.Clear();
60-
BoundsExtensions.GetColliderBoundsPoints(myCollider, inFOVConeBoundsCornerPoints, 0);
52+
inFOVBoundsCornerPoints.Clear();
53+
BoundsExtensions.GetColliderBoundsPoints(myCollider, inFOVBoundsCornerPoints, 0);
6154

6255

6356
float xMin = float.MaxValue, yMin = float.MaxValue, zMin = float.MaxValue;
6457
float xMax = float.MinValue, yMax = float.MinValue, zMax = float.MinValue;
65-
for (int i = 0; i < inFOVConeBoundsCornerPoints.Count; i++)
58+
for (int i = 0; i < inFOVBoundsCornerPoints.Count; i++)
6659
{
67-
var corner = inFOVConeBoundsCornerPoints[i];
68-
if (cam.IsInFOVCone(corner, 0))
60+
var corner = inFOVBoundsCornerPoints[i];
61+
Vector3 screenPoint = cam.WorldToViewportPoint(corner);
62+
63+
bool isInFOV = screenPoint.z >= 0 && screenPoint.z <= cam.farClipPlane
64+
&& screenPoint.x >= 0 && screenPoint.x <= 1
65+
&& screenPoint.y >= 0 && screenPoint.y <= 1;
66+
67+
if (isInFOV)
6968
{
70-
if(debug)
71-
{
72-
Debug.Log("IsInFOVCone returned true");
73-
}
7469
inFOVConeColliderCache.Add(cameraColliderPair, true);
7570
return true;
7671
}
7772

78-
var cornerScreen = cam.WorldToScreenPoint(corner);
79-
xMin = Mathf.Min(xMin, cornerScreen.x);
80-
yMin = Mathf.Min(yMin, cornerScreen.y);
81-
zMin = Mathf.Min(zMin, cornerScreen.z);
82-
xMax = Mathf.Max(xMax, cornerScreen.x);
83-
yMax = Mathf.Max(yMax, cornerScreen.y);
84-
zMax = Mathf.Max(zMax, cornerScreen.z);
73+
// if the point is behind the camera, the x and y viewport positions are negated
74+
var zViewport = screenPoint.z;
75+
var xViewport = zViewport >= 0 ? screenPoint.x : -screenPoint.x;
76+
var yViewport = zViewport >= 0 ? screenPoint.y : -screenPoint.y;
77+
xMin = Mathf.Min(xMin, xViewport);
78+
yMin = Mathf.Min(yMin, yViewport);
79+
zMin = Mathf.Min(zMin, zViewport);
80+
xMax = Mathf.Max(xMax, xViewport);
81+
yMax = Mathf.Max(yMax, yViewport);
82+
zMax = Mathf.Max(zMax, zViewport);
8583
}
8684

87-
// case 1
85+
// Check that collider is visible even if all corners are not visible
86+
// such as when having a large collider
8887
result =
89-
zMax > 0 // in front of the camera
90-
&& zMin < cam.farClipPlane // not too far
91-
&& xMin < cam.pixelWidth // left edge is not too far over
92-
&& xMax > 0 // right edge is not too far over
93-
&& yMin < cam.pixelHeight // bottom edge is not too high
94-
&& yMax > 0; // top edge is not too high
95-
if (debug)
96-
{
97-
Debug.Log($"{myCollider.gameObject.name} {xMin}, {xMax}, {yMin}, {yMax}, {zMin}, {zMax} {cam.nearClipPlane} {cam.farClipPlane} {cam.pixelWidth} {cam.pixelHeight} {result}");
98-
}
88+
zMax > 0 // Front of collider is in front of the camera.
89+
&& zMin < cam.farClipPlane // Back of collider is not too far away.
90+
&& xMin < 1 // Left edge is not too far to the right.
91+
&& xMax > 0 // Right edge is not too far to the left.
92+
&& yMin < 1 // Bottom edge is not too high.
93+
&& yMax > 0; // Top edge is not too low.
94+
9995
inFOVConeColliderCache.Add(cameraColliderPair, result);
10096

10197
return result;

0 commit comments

Comments
 (0)