Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by darthbator · Jul 01, 2017 at 05:39 AM · camerarenderinginvisible

OnBecameInvisible in the Editor?

Does anyone happen to know of a way to deal with on became invisible in the editor? It's a massive pain to relocate my scene camera anytime I want to play the game to make sure I get the correct camera calls. Is there a generally accepted way to handle this particular problem? Is there another "OnWontRender" callback that is called anytime a camera stops rendering an object and not just when no cameras will render the object?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by Bunny83 · Jul 02, 2017 at 04:56 AM

No, there is no real replacement for that callback that does not take the sceneview camera into account. The sceneview camera is just a normal camera, just that it is hidden in the hierarchy.

Depending on what you want to achieve you may be able to use OnWillRenderObject which is called for every camera that is about to render the object. Of course you don't get a call if an object is not rendered by a camera.

However you could manually test if an object is inside the camera frustum. You could use Unity's CalculateFrustumPlanes as well as TestPlanesAABB. However CalculateFrustumPlanes allocates memory for the Plane array.

Instead you could use this extension i wrote:

 // VisibilityTools.cs
 using UnityEngine;
 
 public enum EFrustumIntersection
 {
     Outside,
     Inside,
     Intersecting
 }
 
 public struct Frustum
 {
     public Vector4 l;
     public Vector4 r;
     public Vector4 b;
     public Vector4 t;
     public Vector4 n;
     public Vector4 f;
 
     public Plane left { get { return new Plane { normal = l, distance = l.w }; } }
     public Plane right { get { return new Plane { normal = r, distance = r.w }; } }
     public Plane bottom { get { return new Plane { normal = b, distance = b.w }; } }
     public Plane top { get { return new Plane { normal = t, distance = t.w }; } }
     public Plane near { get { return new Plane { normal = n, distance = n.w }; } }
     public Plane far { get { return new Plane { normal = f, distance = f.w }; } }
     public Vector4 this[int aIndex]
     {
         get
         {
             switch(aIndex)
             {
                 case 0: return l;
                 case 1: return r;
                 case 2: return b;
                 case 3: return t;
                 case 4: return n;
                 case 5: return f;
                 default: throw new System.ArgumentOutOfRangeException("aIndex", "value must be between 0 and 5");
             }
         }
     }
 
     public EFrustumIntersection TestBounds(Bounds aBounds)
     {
         var min = aBounds.min;
         var max = aBounds.max;
         var x = new Vector2(min.x, max.x);
         var y = new Vector2(min.y, max.y);
         var z = new Vector2(min.z, max.z);
         var res = EFrustumIntersection.Inside;
 
         for (int i = 0; i < 6; i++)
         {
             var plane = this[i];
             int xi = plane.x > 0 ? 1 : 0;
             int yi = plane.y > 0 ? 1 : 0;
             int zi = plane.z > 0 ? 1 : 0;
             if (plane.x * x[xi] + plane.y * y[yi] + plane.z * z[zi] + plane.w < 0)
                 return EFrustumIntersection.Outside;
             if (plane.x * x[1-xi] + plane.y * y[1-yi] + plane.z * z[1-zi] + plane.w < 0)
                 res = EFrustumIntersection.Intersecting;
         }
         return res;
     }
     public EFrustumIntersection TestPoint(Vector3 aPoint)
     {
         for (int i = 0; i < 6; i++)
         {
             var plane = this[i];
             float d = plane.x * aPoint.x + plane.y * aPoint.y + plane.z * aPoint.z + plane.w;
             if (d < 0)
                 return EFrustumIntersection.Outside;
         }
         return EFrustumIntersection.Inside;
     }
 }
 
 
 public static class VisibilityTools
 {
     public static Frustum GetFrustum(this Camera aCam)
     {
         var m = aCam.projectionMatrix * aCam.worldToCameraMatrix;
         Frustum res;
         var x = m.GetRow(0);
         var y = m.GetRow(1);
         var z = m.GetRow(2);
         var w = m.GetRow(3);
 
         res.l = GetNormalizedPlane(w + x);
         res.r = GetNormalizedPlane(w - x);
 
         res.b = GetNormalizedPlane(w + y);
         res.t = GetNormalizedPlane(w - y);
 
         res.n = GetNormalizedPlane(w + z);
         res.f = GetNormalizedPlane(w - z);
         return res;
     }
 
     private static Vector4 GetNormalizedPlane(Vector4 aVec)
     {
         return aVec*(1f / Mathf.Sqrt(aVec.x * aVec.x + aVec.y * aVec.y + aVec.z * aVec.z));
     }
 }

It basically provides the same functionality as Unity's methods but uses a struct with 6 plane definitions instead of an array. It also differentiates between outside, inside and intersecting which might also be useful in some cases. Note that the check is based on the axis aligned bounding box you provide (which you usually get from "Renderer.bounds"). That AABB usually is larger than the actual object. Though Unity uses the same for it's visibility check.

To use this extension, just place this "VisibilityTools" script into your project. This allows you to test the visibility of an object against a specific camera. If you need to test multiple objects, make sure you "cache" and reuse the frustum definition you get from GetFrustum. Though keep in mind whenever the camera moves, rotates or is changed in any way you need to refresh the frustum. There's no problem refreshing the frustum once every frame. Though you might want to avoid calculating it several times within a single frame.

 Renderer someObject;
 
 Frustum f = Camera.main.GetFrustum();
 if (f.TestBounds(someObject.bounds) == EFrustumIntersection.Outside)
 {
     // "someObject" is not rendered by the main camera
 }

As additional note: the normals of the frustum planes point "inwards". That means a given point is inside the frustum when the point is on the "positive side" of each plane. Likewise if a point is behind any of the 6 planes(on the negative side) the point is outside.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Jul 02, 2017 at 05:35 AM 0
Share

As alternative when you only worry about the sceneview camera to disturb your testing inside the editor you can use an editor script like this which allows you to easily disable / enable all sceneview cameras:

 // EditorCameraControls.cs
 using UnityEngine;
 using UnityEditor;
 
 public class EditorCameraControls : EditorWindow
 {
     [$$anonymous$$enuItem("Tools/EditorCameraControls")]
     private static void Init()
     {
         GetWindow<EditorCameraControls>();
     }
     int state = -1;
     bool autoDisable = false;
     private void OnEnable()
     {
         bool allOff = true;
         bool allOn = true;
         foreach (var cam in SceneView.GetAllSceneCameras())
         {
             allOff &= !cam.gameObject.activeSelf;
             allOn &= cam.gameObject.activeSelf;
         }
         if (allOn && !allOff)
             state = 1;
         else if (!allOn && allOff)
             state = 0;
         else
             state = -1;
         EditorApplication.playmodeStateChanged += OnPlaymodeChange;
     }
     private void OnDisable()
     {
         EditorApplication.playmodeStateChanged -= OnPlaymodeChange;
     }
 
     void SetCamState(bool aState)
     {
         foreach (var cam in SceneView.GetAllSceneCameras())
         {
             cam.gameObject.SetActive(aState);
         }
         state = aState?1:0;
         Repaint();
     }
 
     private void OnGUI()
     {
         if (state == 1)
             GUI.color = Color.green;
         else if(state == 0)
             GUI.color = Color.red;
         else
             GUI.color = Color.yellow;
         GUILayout.BeginHorizontal();
         if (GUILayout.Button("Enable"))
         {
             SetCamState(true);
             SceneView.RepaintAll();
         }
         if (GUILayout.Button("Disable"))
         {
             SetCamState(false);
         }
         GUILayout.EndHorizontal();
         GUI.color = Color.white;
         autoDisable = GUILayout.Toggle(autoDisable,"AutoDisable","Button");
 
     }
     void OnPlaymodeChange()
     {
         if (autoDisable)
         {
             SetCamState(!EditorApplication.isPlaying);
         }
     }
 
 }

Just place the script in an "editor" folder in your project and open the window from the "Tools" menu. When you enable the "autodisable" toggle the window will automatically disable the sceneview cameras when you enter playmode and re-enable them when you stop playing.

Though keep in $$anonymous$$d while the sceneview camera is disabled the sceneview can't be redrawn properly. That means it can't be used while the cameras are disabled. Though you can press the "Enable" button in the window at any time to re-enable the cameras. Of course this would have an effect on the OnBecameVisible / Invisible callbacks.

avatar image ZAxisTechnology · Jan 11, 2018 at 09:42 PM 1
Share

Thanks for this awesome extension! FYI I think theres a typo here:

 if (plane.x * x[xi] + plane.y * y[xi] + plane.z * z[zi] + plane.w < 0)
                  return EFrustumIntersection.Outside;
              if (plane.x * x[1-xi] + plane.y * y[1-xi] + plane.z * z[1-zi] + plane.w < 0)
                  res = EFrustumIntersection.Intersecting;

I think you should be using y[yi] and y[1 - yi] ins$$anonymous$$d of the xi indices. Thanks again!

avatar image Bunny83 ZAxisTechnology · Jan 12, 2018 at 12:27 AM 0
Share

Yes, you are totally right ^^. It was a copy&paste error. I've fixed it. Thanks.

ps: there was another error in line 74. Originally i returned "Outside" which didn't make much sense.

avatar image
0

Answer by FlaSh-G · Jul 01, 2017 at 09:58 AM

Put this at the beginning of your OnBecameInvisible:

 #if UNITY_EDITOR
 if(Camera.current && Camera.current.name == "SceneCamera") return;
 #endif

The preprocessor directives around the actual line prevent this then-unneccessary test to be compiled into your build.

A more precise solution (not relying on the camera's name) would be to check if Camera.current is referenced in the array returned by SceneView.GetAllSceneCameras().

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image darthbator · Jul 02, 2017 at 12:02 AM 0
Share

This is not the issue. The issue is that the OnBecameInvisible callback is never fired if the scene camera can see the object. Functionally I guess it's fine because this behavior doesn't manifest in builds. However it makes testing in the editor extremely strange. I basically need to unfocus the scene view or else my camera logic code will break.

Is this just not the correct way of monitoring drawn objects for game logic? Are you really mean to check the cameras AABB or monitor isVisible on individual objects every frame?

avatar image
0

Answer by Hexkonst · Oct 26, 2019 at 01:53 PM

     Vector3 viewPos = Camera.main.WorldToViewportPoint(this.transform.position);
     if (viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1)
     {
         hasBeenVisible = true;
     }
     else
     {
         if(hasBeenVisible) Destroy(gameObject);
     }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

103 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to create texture from multiple sprite in unity2d? 0 Answers

Dissable lights per camera? 2 Answers

GameObject invisible at certain camera angles 0 Answers

Rendering the same Render Texture differently to separate cameras 0 Answers

Camera of multiplayer game 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges