Closed david-c-kline closed 2 years ago
In option 2, there is a catch. Depending on the control stack, it is not ensured that the top most item is interactable (ex: text labels on buttons are not).
Do we currently check for this in the RaycastAll method?
From my read of the code, that is handled by the raycast comparer in the prioritization step (which uses the collection of all results returned by the RaycastAll method).
We use Unity UI exclusively for our UI and have done a lot of investigation in to performance and can share some of our findings.
EventSystem.RaycastAll is expensive because there is no broadphase collision detection on Unity UI canvases, so it tests every UI element in the whole scene that has "Raycast Target". So the more UI elements you have the more expensive it is.
Best Practice: Turn off "Raycast Target" on everything apart from interactive elements (buttons, tick boxes, etc) and a background element which defines the shape of a panel. So text, images etc which are there just for visual should have "Raycast Target" disable. You can write simple tools to help with setting the flag as appropriate. In addition to the above best practice we have a custom graphics raycaster which uses the bounds of a canvas as a broadphase collision test. If you ensure all UI is inside a well fitted canvas, the UI elements themselves only get tested when the pointer is on the canvas.
These two approaches combined makes the UI raycast cost negligible for even very complex UIs.
One other thing to note is that default number of segments for a Line Pointer is 2 (at least in MRTK v2.2) for what is essentially a straight line, that's 2 times as many raycasts as are needed.
As for direct feedback to your suggestion: I would favour communication of best practices over magic options that can have undesirable and often confusing side effects. Ignore all Unity UI - If UI is "visual only" then the Graphics Raycaster can be removed from the canvas and you'd have no cost. Similar to your suggestion though, this would result in no indication that the cursor on the UI, so disabling all raycast targets apart from a single background/panel element would be better practice. Return the top most item - If you have enough information to use this option without running in to the cons, then you probably have enough information to follow the best practices outlined above. If you don't have enough information, you're just inviting inconsistent behaviour and not knowing why.
Adding to what @WikkidEdd has noted above, I suggest making sure that the user understands the Raycast Target and Graphics Raycaster costs as explained here.
@WikkidEdd and @tank-t-bird, thank you for the input! This is fantastic feedback! From what you describe, the best approach is likely to expand our documentation and provide a link to it from the Input System inspector UI.
Could a check be added to the Optimize Window to call out when canvas UI has unneeded Raycast Targets?
@KevinKennedy, I like the idea. It would conceivably have a list of known non-interactable elements and check to see if any of them have RaycastTarget enabled.
Better documentation would be helpful on setting up both Unity UI as well as configuring MRTK UI elements with Screen Space Overlay as World Space often isn't a good experience on mobile.
This issue has been marked as stale by an automated process because it has not had any recent activity. It will be automatically closed in 30 days if no further activity occurs. If this is still an issue please add a new comment with more recent details and repro steps.
MRTK's support for Unity UI relies upon a potentially (up to 1.5ms) expensive API call (EventSystem.RaycastAll) per pointer. This can add up rapidly and cause the focus provider to consume significantly more CPU budget than the target for all of MRTK (~4ms).
Thanks to fantastic community feedback, we have landed on a plan to: