- Home /
Detect if entity is visible - renderer.isvisible will not work!
To put it simply, I need to detect if an entity/it's children are visible or not by the camera. I've been using renderer.isvisible, however it simply won't work. It's extremely glitchy- sending off signals that it isn't visible when it's right in-front of the camera, and thinks it is visible when it's no-where in sight. I've been digging for the past few weeks for a solution, and all that I've found is something to do with GeometryUtility.TestPlanesAABB to check if it's visible- but can't figure out quite how. The example on the Unity page even says it detects if it's visible, but I've had absolutely no luck in getting it to work- even in an new empty script. An alternative, or a working example that I could throw in here would be amazing; I don't care what it is, as-long as it's precise.
TL~DR: I need a way to precisely detect if an object is visible or not. Doing it by renderer is horrible unstable/un-precise and will not work for this project.
Any help would be greatly appreciated, as I can't continue any further on my project without a solution to this. I'd also like to mention that my entire project is in JavaScript, and I do not understand more than basic syntax of C#.
Answer by aldonaletto · Oct 21, 2013 at 12:15 PM
renderer.isVisible works fine, but it actually only tells whether the object is inside the viewing angle of any camera (including the scene view's camera). It doesn't know if an object is being obscured by another one - a character completely behind a wall still reports isVisible = true if in front of any camera. You can use the events OnBecameVisible/OnBecameInvisible instead: they are called whenever isVisible changes state to true/false.
The isVisible property probably is set by the frustum culling process, which takes place when a camera is about to render the scene: all objects are tested against the frustum planes with an internal version of TestPlanesAABB (actually, their renderer.bounds are tested).
If you must know whether an object is inside the viewing frustum of one specific camera only (ignoring other cameras), the test must be made manually (attach this to the object):
function Update() {
var planes: Plane[] = GeometryUtility.CalculateFrustumPlanes(Camera.main);
if (GeometryUtility.TestPlanesAABB(planes,renderer.bounds))
Debug.Log("Object inside frustum");
else
Debug.Log("Object not visible");
}
But if you must know whether the object is obscured, things get way more complicated - actually, there's no reasonable way to check if any pixel of the object is visible (maybe analyzing the depth buffer with some specialized shader).
As far as the isVisible method goes, I'll look back through my code to see if it's possibly a mistake on my end, but currently it is terribly unstable. It triggers that it's looked at when it's nowhere in sight, and thinks it is not looked at when it's right in-front of the camera. Either way..
I tried the above script, however it spat back an error saying Planes is an unexpected token. I tried making planes/Camera a variable as seen in the example Script Reference, but it still returned that planes was an unexpected token. Since it looks like this accomplishes the same thing as the Script Reference linked above, I tried that example, but it still didn't work.
If someone could please fix up this example a bit more so it properly works, it'd be greatly appreciated as I'm stuck until then.
$$anonymous$$y bad! I forgot the var keyword before planes - answer fixed now. Unfortunately, CalculateFrustumPlanes allocates some memory each time it's called (about 400 bytes), thus doing this in Update will cause more frequent garbage collections. If you're using only one camera, I strongly recommend to use OnBecameVisible/Invisible ins$$anonymous$$d: these events only occur when isVisible changes, thus no time is wasted checking this property every frame and no memory allocation takes place. About the reliability: OnBecameVisible may occur even when the object is out of view (caught by another camera, or barely touching the frustum), but OnBecameInvisible only occurs when the object really goes out of any camera's frustum.
Also so you know, the Editor's scene view tab camera will activate isVisible if the tab is not hidden.
Oh God! I was frecking out trying to understand WHY the hell the isVisible worked for a while and then, don't... Thanks!
Like it says in the docs, an object can be considered visible even if only its shadow is being rendered, so that was my issue with GetComponent(Renderer).isVisible.
$$anonymous$$aybe Unity should add an option so isVisible can ignore the shadows if asked to.
While they don't, I used @aldonaletto 's solution and it fixed my problem. Thank you.
Answer by Cherno · Oct 21, 2013 at 11:01 PM
As a workaround, you could do raycasts every few frames against all relevant gameobjects in the scene (possible if there's not too many at once):
var fov : float = 45.0;
LoSBlockMask : LayerMask;
hit : RaycastHit;
function CheckLineOfSight (target : GameObject) : boolean
{
if (Vector3.Angle(target.transform.position - transform.position, transform.forward) <= fov)
{
if(Physics.Linecast(transform.position, target.transform.position, hit, LoSBlockLayerMask) == false)
{
//target is inside fov and a line from the player's front towards the target's origin is not interrupted by los-blocking obstacles specified in LoSBlockMask
}
}
}
Answer by Speedomon · Apr 22 at 08:26 AM
I have/had this problem. If it's not the scene view, it's probably the shadow. While IsVisible works pretty accurate for geometry itself, the shadow can turn it to true even if is still far outside of the camera's view. I guess there is very rough estimation whether a shadow should be visible that tends to be on the safe side rather than accurate. Try deactivating shadows on your geometry to test if that's the issue.
My workaround is to hide a tiny cube with no shadow inside the geometry and test IsVisible for the cube's renderer instead of the original mesh' one. It's a bit clunky, but basically works for me. You could also make the cube/sphere as big as you want and make its material transparent.