Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Detecting if a visual element is off screen

Discussion in 'UI Toolkit' started by jnhackleman_unity, May 4, 2022.

  1. jnhackleman_unity

    jnhackleman_unity

    Joined:
    Sep 16, 2021
    Posts:
    20
    Hi all,
    I'm scratching my head on how to detect if a visual element (with no direct position values) is on screen or off screen.

    I understand for game objects it's pretty easy:
    Code (CSharp):
    1.  
    2. var pos = Camera.main.WorldToScreenPoint(myObject.transform.position);
    3.             bool isOffscreen = pos.x <= 0 || pos.x >= Screen.width ||
    4.                 pos.y <= 0 || pos.y >= Screen.height;
    5.  
    But how I can do the same thing for a visual element?
    doing:
    Code (CSharp):
    1. Camera.main.WorldToScreenPoint(myVisualElement.transform.position);
    - doesn't seem to give the same results
     
  2. SimonDufour

    SimonDufour

    Unity Technologies

    Joined:
    Jun 30, 2020
    Posts:
    529
    There are automatic scaling based on a few factors on the panel. If you are not aiming to preserve aspect ratio and want to keep things simple, you could set a fixed scaling of 1 in your PanelSettings for your method to work. Use the bounding box value of the element instead of using the value from ITransform, as the transform you are fetching is an offset fed to the layout engine and not the final position of the element. Finally, I think you will also need to flip the Y axis. This is a quick answer to unblock you, but don't hesitate to ask more question if you need further help.
     
  3. jnhackleman_unity

    jnhackleman_unity

    Joined:
    Sep 16, 2021
    Posts:
    20
    Hi, thanks for the reply!
    We aren't going to set a fixed scale for the game so I don't think that will work.
    regardless, I feel like the methods are all there somewhere, but all these cameras, and screens, and panels, and transforms, matrixes, rects... it's all just nutty to get through.

    I may end up just calculating the resolved offsets recursively to the root element, but I feel like doing that for all elements every frame is not going to be optimal.

    Any other ideas?
     
  4. SimonDufour

    SimonDufour

    Unity Technologies

    Joined:
    Jun 30, 2020
    Posts:
    529
    visualElement.worldBound
    contains an AABB of the element relative to the panel's root, so you don't need to calculate it yourself to get the boundaries of the element.

    If you just want to know if the location is in the camera, and not convert screen coordinates, you can ignore the scaling and just compare with the size of the root visual element after the layout. You will need to create a dummy Rect for the screen and use Rect.Overlaps
     
  5. jnhackleman_unity

    jnhackleman_unity

    Joined:
    Sep 16, 2021
    Posts:
    20
    Thank you so much!

    This does exactly what I need and it's cheap:

    Code (CSharp):
    1.    
    2. public static bool IsElementPartiallyOffScreen(VisualElement pScreenRoot, VisualElement pElement)
    3.     {
    4.         //Detect if any portion of it IS on screen
    5.         //var overlaps = pScreenRoot.worldBound.Overlaps(pElement.worldBound);
    6.  
    7.         //See if any portion of it is NOT on screen
    8.         return pElement.worldBound.x <= 0 || pElement.worldBound.xMax >= pScreenRoot.worldBound.width ||
    9.             pElement.worldBound.yMin <= 0 || pElement.worldBound.yMax >= pScreenRoot.worldBound.height;
    10.     }
     
    SimonDufour likes this.