Search Unity

Question How Can a GameObject Detect if It Is Culled?

Discussion in 'Scripting' started by redapplesonly, May 23, 2023.

  1. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    51
    Hi all, I have a GameObject with a LOD Group component and another 2D Box Collider component. In my game, the Main Camera may zoom out far enough for the GameObject to become culled, which - as I understand it - means the GO is no longer rendered in the scene. But the 2D Box Collider is still active, which means that my player can still click on the GO even though it is invisible. That's no good.

    I was surprised that I couldn't find a `IsCulled()` method in the Unity documentation, as that seems like a simple thing to determine. I wrote my own (below) but I dislike this method because it seems like a performance hog, potentially O(n^2) for every LOD Level and Rendender. Can someone recommend something - anything! - better? Thank you.

    Code (CSharp):
    1.     private bool IsCulled()
    2.     {
    3.         LODGroup lodGroup = this.GetComponent<LODGroup>();
    4.         if (lodGroup != null)
    5.         {
    6.             Transform lodTransform = lodGroup.transform;
    7.             foreach (Transform child in lodTransform)
    8.             {
    9.                 var renderer = child.GetComponent<Renderer>();
    10.                 if (renderer != null && renderer.isVisible)
    11.                 {
    12.                     return false;                // At least one renderer is visible
    13.                 }
    14.             }
    15.         }
    16.         return true;                // All rendereres are not visible
    17.     }
     
    AntonioModer likes this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    For what camera? To what end? Most people don't care so the engine would be doing all this extra work to set the isCulled bit just for occasional use.

    There are OnWillRender style calls available to MonoBehaviours and Cameras, perhaps other things... take a google around and see.
     
    redapplesonly likes this.
  3. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    51
    @Kurt-Dekker Thanks for writing, yours are good questions. I'm concerned about objects seen from the Main Camera, and if any GameObjects are culled, I want them to no longer be clickable. Disabling their 2D Box Colliders should do it.

    OnWillRender() looks promising, thank for the lead!
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Not sure why you have to do all that...

    Just:

    - only allow clicking onscreen... this ensures the ray will be in-frustum
    - if you absolutely must, provide camera farclip distance as raycast maxDistance

    Done...?
     
    orionsyndrome likes this.
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,004
    It depends on how you're "zooming". If you move the camera backwards the object will ultimatively be behind your far clipping plane and in that case, yes it would be culled. When an object is no longer rendered, you will receive the OnBecameInvisible callback on scripts attached to the renderer. When it gets back into the viewing frustum OnBecameVisible would be called. Those can be used to disable / enable the colliders.

    However note that an object ONLY becomes invisible when NO camera is seeing it. This includes SceneView cameras as well. So if you look at that object with the scene view camera, the object would not be culled.
     
    redapplesonly and orionsyndrome like this.
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    I agree with Kurt's maxDistance.
    Presumably you're casting rays which interact with the collider, so why cast them at float.PositiveInfinity?
     
    redapplesonly and Nad_B like this.
  7. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Note OnBecomeVisible/OnBecomeInvisible depend on the renderer's bounding box, which might not be the same as the 2D box collider bounds.
     
    redapplesonly likes this.
  8. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    51
    @Bunny83 Thanks for writing Bunny, you're a godsend for Unity newbies like me.

    Your post really got me thinking. My game only has one Main Camera, and when I talk about zooming out, its that to camera that I'm referring. And currently, when I zoom out far enough, I can see my GameObjects no longer becoming rendered, although they are still clickable.

    But I never thought about the Scene View Camera! That camera is not moving at all while the Main Camera is doing its thing. And sure enough, when I watch both camera as I zoom out on the Main Camera, the Scene View is still rendering my GameObjects. So that's prob why my scripts never call OnBecomeInvisible().

    I just need to figure out how to disable the Scene View Camera. Disabling it in the Gizmos drop-down window does nothing, alas...
     
  9. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    Try hiding (as in docking it to the same area as Game, but not actively looking at it) or closing the Scene View entirely. I believe this will disable the scene camera.
     
    redapplesonly and Bunny83 like this.