I’m having issues with world space canvases not rendering correctly since it doesn’t work based on z depth, unfortunately. So a canvas in front of another canvas can render behind it because its all based on a static sort order instead of world position.
My only idea right now is making a script that updates sort order based on distance from the camera, but it wouldn’t work well for overlapping objects as it would be basing it only on the center of the object instead of any particular point on it. Also concerned if that might start breaking batching or raising the performance cost of the canvases or something
Can you put them all on the same render/sort order? I’d need a good sample project, but we have some very world space UI heavy scenes with UI in the world, attached to the headset, and attached to each controller, and it works.
From what I recall, if sort/render order is the same, it will then fall back to z-depth.
Hmm so if I recall correctly, I started changing the sort order so that SpriteRenderer’s/world text would be able to batch, and then that caused needing to change the sort order of canvases as well. So I think your proposed solution might work, but would break batching of all the non-canvas objects?
This one is running out of my domain, but potentially.
I’m not sure all the cases that the UI is able to batch and when it isn’t, but you may need to make a decision.
Normally, the shader used for UI doesn’t depth write. That is what causes later UI draw calls to just splat over top regardless of true depth. It depth checks, so that physical objects can occlude, but UI on UI occlusion isn’t there. You can try to pick a shader that does a depth write (+ alpha test since a lot of UI has soft edges), and this should also solve your issue, since it means that UI drawn in a later batch will have depth information so it can know not to draw over top. Since depth writing is an all or nothing thing, it can come with some other complications such as relatively jagged edges.
Normally UI just renders each sort order block back to front, so depth is pre-processed and irrelevant at render time. But since XR has constantly moving canvas’ in 3d space that ‘back to front’ isn’t as consistent as it is for a screen-space UI. If you need to draw text, then an image occluding part of the first text, then a second text, then the system can’t batch those 2 text UIs. This process also gets confused when you have intersecting UI, where the UI is both in front and behind another one depending on the pixel. Forcing the sort order to force batching just isn’t as easily predictable because you can’t look at the UI and just ‘know’ which elements will be on top of which for the entirety of gameplay.
So, depending on your specific setup, you may need to either ditch the sort order and lose out on batching performance, or play with depth write and alpha test shaders to try and get your UI’s depth info into the depth buffer. I can’t really give you a strict direction because it can depend on your project, performance constraints, and what you can get away with UI wise. XR Interaction Toolkit also has this issue by the way. It’s still in preview, but the way the ray interactor interacts with the UI has similar sorting problems and is on the list to resolve before releasing the non-preview version.
Not a great answer, but hopefully it explains the problem. I’m not sure there is a name for it, but it’s pretty prevalent in how 3D graphics work and how they deal with transparent objects. Your sprites/UI are effectively transparent objects because it’s effectively a 3D quad with an image with transparency as a texture.
Alright, thanks for the detailed reply. I’ll look into trying out some different options and see what I can figure out.
I have a follow up question.
Is there a way to make the mandatory world space UI always be on top of everything? even game objects?
I have a simple HUD that gets blocked by interactable gameobjects. I need the UI HUD to behave as a Screen Space overlay. Any way to sort the UI Canvas to always be on top regardless of what comes infront of it?
A material? A sorting layer that works for both UI and objects?
The Custom Pass(HDRP as im using) is too confuing to use. it needs more tuts to be able to function. As it has a mind of its own. Any other way to fix this?
Haha hi @emrys90 , did you find any solution to this issue since then? I found that some people report having to use a group of canvases fixed it but definitely not for me.
The only solution I found was making a script that updates sort order based on distance from the camera.