Search Unity

Is There Some Trick to "CullingGroup.onStateChanged"?

Discussion in 'Scripting' started by cassius, Dec 19, 2020.

  1. cassius

    cassius

    Joined:
    Aug 5, 2012
    Posts:
    125
    I've been at it for days and can't seem to get onStateChanged to happen except for during initialization within either Start() or OnEnable().

    Is there some trick to CullingGroup.onStateChanged - or maybe I just don't understand how it works? I must be missing a piece of the puzzle. I've gone as far as to putting "group.onStateChanged = OnStateChanged;" into Update() but even that didn't do anything. Tried about a dozen sample scripts from github etc and none update in 2019.4.x for me.

    Here's what I currently have. Thanks for any and all help!

    Code (CSharp):
    1.      public static CullingGroupManager Instance;
    2.      public float radius = 1;
    3.      public CullingGroup group;
    4.      public BoundingSphere[] spheres;
    5.      public RegisterInCullingGroup[] objects;
    6.      public int count;
    7.      void Awake()
    8.      {
    9.          Instance = this;
    10.          group = new CullingGroup();
    11.          group.targetCamera = Camera.main;
    12.          objects = FindObjectsOfType<RegisterInCullingGroup>();
    13.          spheres = new BoundingSphere[objects.Length];
    14.          count = objects.Length;
    15.          for (int i = 0; i < count; i++)
    16.          {
    17.              spheres[i] = new BoundingSphere(objects[i].transform.position, radius);
    18.          }
    19.          group.SetBoundingSpheres(spheres);
    20.          group.SetBoundingSphereCount(count);
    21.          group.SetBoundingDistances(new float[] { 10f, 50f });
    22.          group.onStateChanged = OnStateChanged;
    23.      }
    24.      // Do whatever tasks I need when the Culling Group state changes
    25.      private void OnStateChanged(CullingGroupEvent _event)
    26.      {
    27.          if (_event.hasBecomeVisible)
    28.          {
    29.              Debug.LogFormat("Sphere {0} has become visible!", _event.index);
    30.              objects[_event.index].gameObject.SetActive(true);
    31.          }
    32.          else if (_event.hasBecomeInvisible)
    33.          {
    34.              Debug.LogFormat("Sphere {0} has become invisible!", _event.index);
    35.              objects[_event.index].gameObject.SetActive(false);
    36.          }
    37.      }
    38.      void OnDestroy()
    39.      {
    40.          group.Dispose();
    41.          group = null;
    42.      }
     
    shuntecoud likes this.
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    It seems you're missing CullingGroup.SetDistanceReferencePoint. Looking at the CullingGroup code in my project, I call SetDistanceReferencePoint every Update() with the camera position.

    If this doesn't help, here are a few things you might want to check:
    • Is Camera.main the correct camera? Perhaps you have multiple cameras and one incorrectly is tagged as main camera too.
    • Are any objects found?
    • Is the radius greater than 0
     
  3. cassius

    cassius

    Joined:
    Aug 5, 2012
    Posts:
    125
    Thanks for the reply.

    I've added CullingGroup.SetDistanceReferencePoint into Update() and added in my camera's transform for position but still no luck.
    • Verified the correct camera for Camera.main - also set up a variable to hold the applicable camera (only one in the scene, fresh scene) to pass in for extra measure.
    • All the relevant objects are found. I call "onStateChanged" in Awake() to get things started and that reports things correctly in my debug log output showing correct output for "hasBecomeVisible". But only once.
    • The radius was set to 1 in code, and 10 in Inspector
    If you happen to have any other suggestions I'm all ears (eyes I suppose). But thanks for the help so far.
     
  4. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    I know this is old but are you sure that the scene camera is not looking at the objects in your CullingGroup. OnBecomeVisible won't work correctly if objects are also visible in the scene camera. This applies to Renderers but I assume it's same behaviour for CullingGroup. Try pointing the scene camera somewhere where none of the CullingGroup objects are visible in that camera.
     
  5. cassius

    cassius

    Joined:
    Aug 5, 2012
    Posts:
    125
    It's a pretty old thread and I ended up abandoning the idea of using CullingGroups for what I was doing. If memory serves, I definitely tested with the scenario where objects would be visible by the camera and where they could not be. So I'm still uncertain what had happened and why it wasn't working for me.

    But thanks for the assist nonetheless!
     
  6. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    NP. Just wanted to make the distinction between the game view window in Unity and the scene view window in Unity. If you can see your objects in the Scene view window it's basically like your game camera sees them, it fires the OnBecomeVisible events. Which messes up the OnBecomeVisible. So just to make sure I'm clear I meant that you should not see your objects in the scene view window, otherwise things will behave strangely. ;)
     
    shuntecoud likes this.
  7. cassius

    cassius

    Joined:
    Aug 5, 2012
    Posts:
    125
    Oh! I misunderstood you originally. I think you may be on to what my problem was at the time. I don't remember with 100% certainty that I also moved my Scene camera out of view as well, but I think I did.. I'm reading "scene view" in your post and thinking "game camera view". But now I know now exactly what you're talking about. If I had any of my relevant code around still I'd whip it up and test, but unfortunately I removed that from my game about a year ago. :(
     
  8. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    For sure man, no worries. Just wanted to let you know, in case in the future you decide to use CullingGroup or anyone else runs into something similar, they'll know to check this as a possible solution.
     
    cassius likes this.
  9. dirtypwnography2

    dirtypwnography2

    Joined:
    Sep 20, 2021
    Posts:
    14
    This doesn't really cull anything from rendering. All you're doing at the end of your script is just enabling or disabling the gameObj and that is why it is/is not visible. The problem here is that by disabling the gameObj it would be disabled to all cameras. IDK if once you disable the game obj tho the camera will still be able to pick up on if it is visible or not. You could use the transform.position of the gameObj and cross reference it by the field of view bounds for what the camera can currently see based on its location and zoom (That's kind of a hassle tho, trust me). Then use the transform.position as a determining factor if the game obj should be enabled or not.

    You could eliminate a lot of this hassle by simply adding the gameObj's to a List. Then run a foreach code where you do something along the lines of the following. Obviously modify this code/idea to fit your particular script.
    foreach(var obj in selectedList
    {if(obj.GetComponent<Renderer>().isVisible == true)
    {"than do the blah blah blah's here";}
    }

    of you could run it in the Update() method if you wanted, it would look something like this

    if(selectedList[0].GetComponent<Renderer>().isVisible == true)
    {
    //This is the same thing as what you're doing in the above. The gameObj is culled from the render pipeline. However, it // is not really the act of culling something because now no other camera can see this gameObj either.
    selectedList[0].SetActive(true);
    //This would be the better idea. Since all we've done is just change the transparency of the obj
    selectedList[0].GetComponent<Image>().color = new Color32(255, 255, 255, 0);//for images
    // -or-
    selectedList[0].GetComponent<SpriteRenderer>().color = new Color32(255, 255, 255, 0);
    //for things with sprite renderers
    }
    else if(selectedList[0].GetComponent<Renderer>().isVisible == false)
    {selectedList[0].SetActive(false);}