Immediate mode canvases randomly draw op top of or below other IM draw calls

Avatar
  • updated

I'm using Shapes to draw complex graphs and other stuff in 3D space.

I'd like to also use Shapes for conventional screen space UI and just learned about the IMCanvas experimental feature.

The basic concept seems to be just what I need, but there's some issues preventing its use.

First of all, the IMCanvas renders below my other Shapes IM draw calls. At least sometimes. It seems random.

In the screenshot below I have my graphs rendered in 3D space using immediate mode (not Canvas).

I copied the health bar etc. from the demo scene into this scene and it renders below the graphs rather than on top. This is using a Screen Space - Overlay canvas.

Image 913

Edit: It appears that if it renders under, then if I deactivate the IMCanvasSample component and activate it again, it now renders over. Which makes me think it's something like the last registered IM user, which seems brittle.

A second issue which I don't know whether is related or not:

I switch between several cameras. When I deactivate one camera tagged MainCamera and at the same time activate another camera tagged MainCamera, the IMCanvas stops rendering. Once the original camera is activated again, the IMCanvas renders again. At least this is what appears to be happening. This is despite the canvas being Screen Space - Overlay as opposed to Screen Space - Camera, and so in theory should not relate to specific cameras.

To make sure it's not world objects occluding the IMCanvas objects, I tried looking at the sky and setting the camera to Don't Clear, but still there's no IMCanvas objects drawn.

Reporting a bug? please specify Unity version:
2022.3.62
Reporting a bug? please specify Shapes version:
4.5.1
Reporting a bug? please specify Render Pipeline:
Built-in render pipeline
Avatar

Update: I tracked down the issue with the IMCanvas not rendering for one of my cameras.


It's because the ImmediateModeCanvas.GetOverlayToWorldMatrix method does not account for the fact that a camera's near clip plane does not scale with the scale of the GameObject the camera is attached to.

I had a camera with a scale of 10 (because the larger Prefab instance it's attached to is scaled up as a whole). Since the IMCanvas is set to be at a distance half way between the near and far clip plane, the TransformPoint method sets the origin far beyond the far clip plane.

float planeDistance = ( cam.nearClipPlane + cam.farClipPlane ) / 2;
Transform camTf = cam.transform;
Vector3 forward = camTf.forward;
Vector3 origin = camTf.TransformPoint( 0, 0, planeDistance );

If instead the last line is changed to this:

Vector3 origin = camTf.TransformPoint( 0, 0, planeDistance / camTf.lossyScale.z );

Then the UI remains visible regardless of which camera is active.