@@ -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