How to detect when a whole object is not in sight?

I have tried using:

void OnBecameInvisible(){
//code
    }

But that works as soon as any part of it goes out of sight, is there a way to run code when the whole object is out of sight?

I guess you’re mixing something up. OnBecameInvisible definitely don’t trigger before the whole object is invisible (incl. all stuff like shadows and such).

I use OnBecameInvisible for a few objects in my own game and it works, just as Duugu said. Initially I did noticed that objects I had setup to break into several pieces would disappear into nowhere all of a sudden even though they were in view. I believe it was due to the renderers bounds were outside the camera frustrum but some of the mesh pieces had fallen outside those bounds. So perhaps it could have something to do with it?

If you can’t seem to find a simple solution for it though you could always write something to calculate if the object is inside the cameras view frustrum though. I did something similar to create an AI field of view a long time ago and determine what was inside of it, don’t remember exactly how I did it though but it should be possible to do something similar for your problem, try a google search for it. :slight_smile:

You can do it like this, change camera and renderer as necessary.

frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
bool visible = GeometryUtility.TestPlanesAABB(frustumPlanes, renderer.bounds);

The nice thing about this is that it works for a specific camera, as opposed to for example Renderer.isVisible, which will return true even if the renderer is only visible in the editor viewport.

1 Like

This doesn’t seem to work i’m getting a bunch of errors and Could you explain to me what that script does and how it works. I’ve never even heard of GeometryUtility before.

I think i found what could be the problem, when i was watching to see what could be wrong i found out that for some reason when the camera view goes half way past the object renderer it returns OnBecameInvisible.
I also found out that the actual view is bigger then the camera view box in scene window. how do i solve these problems?

OnBecameInvisible works for both the Scene and Game camera if you’re in the Editor. If it exits the view of the scene camera, even if it is still visible to your game camera, it will be called. Is that possibly the source of your frustration?

Seems I didn’t include the datatype for the first line, should be

Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);

This generates a set of planes that describes the cameras frustum, basically the visible volume of the camera.

The second line

bool visible = GeometryUtility.TestPlanesAABB(frustumPlanes, renderer.bounds);

Then checks if the specified renderers bounds is inside this volume. The variable renderer should be replaced with whatever renderer you wish to check, you normally get this with GetComponent or GetComponent etc.

EDIT: Additional info about the frustum here Unity - Manual: Understanding the View Frustum

I’m getting these errors when i try that:

  1. error CS0117: Camera' does not contain a definition for main’
  2. error CS1502: The best overloaded method match for `UnityEngine.GeometryUtility.CalculateFrustumPlanes(UnityEngine.Camera)’ has some invalid arguments
  3. error CS1503: Argument #1' cannot convert object’ expression to type `UnityEngine.Camera’

And do i need this in “Update()” or “Start()”?

No, i can see the objects disappear around the edges of camera whether its in scene view or not.

That’s strange, there should be a Camera.main, see this page in the docs Unity - Scripting API: Camera.main

You could try creating a variable for the camera and assigning it in the inspector instead

public Camera myCamera;
...
Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(myCamera);

You should do it when you need to determine if the object is visible, so probably update unless your camera never moves, in which case you can do it in start and just keep it in a private variable.

I still get:

  1. error CS1502: The best overloaded method match for `UnityEngine.GeometryUtility.CalculateFrustumPlanes(UnityEngine.Camera)’ has some invalid arguments
  2. error CS1503: Argument #1' cannot convert Camera’ expression to type `UnityEngine.Camera’

I’ve tried casting it to camera with (Camera)myCamera but it still gives me error.

You don’t happen to have a class in your own project named Camera perhaps?

Ahh… that was the problem, thanks!

But this doesn’t seem to work as expected. Nothing is rendering at all and visible is not returning correct value.

Would it be possible for me to just create a sensor around the edges of cameras view because this invisible objects thing is only happening on the edge of the camera, and how would i do that is there someway to align a game object to a cameras view edge?

This shouldn’t affect rendering at all, if nothing is rendering then something else is wrong.

Well it’s possible, but much more difficult. It’s sort of the same thing anyway. CalculateFrustumPlanes will return the planes that represent the edges of the camera. You can use these any way you want, but the most effective is to do an AABB test with the renderers bounds, which is what TestPlanesAABB does.

I set up my code so it doesn’t render if out of view like this:

    void OnBecameInvisible(){
        if (stay == false) {
            foreach (Transform obj in transform) {
                obj.GetComponentInChildren<MeshRenderer> ().enabled = false;
                obj.GetComponentInChildren<BoxCollider> ().enabled = false;
            }
        }
    }

And it works except that edges around camera, the objects are invisible. When i try your way:

Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(myCamera);
        bool visible = GeometryUtility.TestPlanesAABB(frustumPlanes, GetComponent<Renderer>().bounds);
        if (visible == false) {
            if (stay == false) {
                foreach (Transform obj in transform) {
                    obj.GetComponentInChildren<MeshRenderer> ().enabled = false;
                    obj.GetComponentInChildren<BoxCollider> ().enabled = false;
                }
            }
        }

It doesn’t work.