- Home /
How to properly use Renderer.OnBecameInvisible for Culling objects off screen?
Hi,
Found an excellent post about checking "Is target in view frustrum". If i understand it correctly, we would stop rendering of an object by disabling its Renderer when off screen. But as soon as i do this ..
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void OnBecameInvisible() {
GetComponent<MeshRenderer>().enabled = false;
}
void OnBecameVisible() {
GetComponent<MeshRenderer>().enabled = true;
}
}
.. and the object leaves camera frustrum, Its Renderer does not dispatch OnBecameVisible again, once it later again enters the camera frustrum - well, thats obvious, since we disabled it in the first place - so a disabled Renderer would not fire OnBecameVisible.
What gives? Using this culling technique i cant do the culling.
Further more i wanted to actually disable the whole GameObject (not only its Renderer) when it leaves frustrum. Any thoughts on the best-practise implementation-vise here? I guess you cant use Renderer's isVisible/OnBecameVisible/OnBecameInvisible? Is using WorldToScreenPoint favored approach in this case? Is there better approach than disabling whole GameObject performance-vise?
Brainstorm please, tested methods preferred!
Answer by HarshadK · May 20, 2016 at 02:24 PM
You don't have to disable the Renderer when gameobject is not shown on the screen as it will not be rendered anyway because of frustrum culling.
We can provide you with method to use based on what exactly you want to achieve here.
@Harshadk thanks for the feedback, i did suspect his, so that is awesome. I could disable everything else in the GameObject ins$$anonymous$$d (like scripts colliders etc). Im reading that GameObject.SetActive is extremely expensive operation anyways (1, 2, etc) - as i was considering using WorldToScreenPoint manual culling with complete gameObject.SetActive(true/false), but alas i might wanna disable stuff more granularly inside the GO.
$$anonymous$$y case is a 2.5D platformer (1 camera, 1 plane - simple), i have lots of primitive objects on screen at once (up to 1k objects constantly), with a lot of stuff offscreen. Im using StaticBatchingUtility for batching everything thats batchable, that helps, but every object has some scripts and collider(s) attached to it, and in my testing, this eats up CPU even when the objects are offscreen.
So next im gonna test disabling these on offscreen objects: 1) colliders 2) scripts 3) anything else except Renderer
And ill get back here with results. Let me know if you think there is better approach so i can try it as well.
Thanks!
As @Baste said it would not be wise to just perform optimizations like disable/enable all components blindly as there is a cost associated with enabling/disabling components which cumulatively might become more costly if you are doing it for thousands of objects than actually not doing it.
So first check for pain points and then try to optimize them. You can also use optimization techniques like collision layers to reduce unwanted collision checks which is better way than enabling/disabling colliders as collision layer optimization will work even if the objects are on screen where optimization are actually important.
Ill accept your answer as it was my misunderstanding that Frustrum culling would render offscreen object IF its Renderer is active, which isnt the case (Renderer script can be kept active for OnBecameVisible trigger and Frustrum culling will ensure the object wont render offscreen). So the question was answered by you correcting my wrong assumption, thanks.
Answer by Baste · May 20, 2016 at 02:44 PM
As @HarshadK said, the object's renderer is automatically culled as long as no part of it is visible on any camera.
It makes sense to "cull" (turn off) expensive components on your GameObject when they leave the view. If you have a NPC with a patrolling script and a navmesh agent, you can turn off the script and agent when they leave view. Projectors also make sense to turn off - as long as they're projecting onto a mesh that's visible (like a big ground mesh), they will cause extra draw calls even though the projector itself isn't visible.
As with everything that's performance related, optimizing before you know what's causing bad performance is the stupidest thing you can do. If your game's running slowly, open the profiler and check what's slow. Making a blind guess and doing a bunch of manual culling of objects is probably not going to help, and cost a lot of time and effort.
@Baste "As with everything that's performance related, optimizing before you know what's causing bad performance is the stupidest thing you can do" Well said x)
$$anonymous$$y case is primitive objects with colliders and scripts on them, its that simple. Ive noticed full screen of these runs well. Other 2 full screens of them off camera and it runs pretty bad. $$anonymous$$ust be the active Scripts like $$anonymous$$onobehaviours waiting for Collider triggers etc eating empty CPU cycles on every frame. Thanks for the examples with projector and navmesh, might be useful later.
Your answer
Follow this Question
Related Questions
Custom frustum culling with scissoring 0 Answers
OnBecameVisible() not working as I'd hoped 1 Answer
Occlusion Culling issue (works like Frustum Culling) 0 Answers
Occlusion Culling Question 1 Answer