How can I hide a world space canvas for specific cameras?

I want to have full control over what the canvas/objects the camera can see in a split-screen game. I created a class to hide/show objects for specific cameras by disabling/enabling objects in RenderPipelineManager callbacks. Everything works fine until I try to hide an object containing UI elements. The object becomes invisible, but the UI still renders for any camera (excluding the scene view camera for some reason, but that’s not really important).

It seems that the canvas has a different rendering cycle, because I even tried wrapping the UI with a CanvasGroup and changing its alpha to hide it, but that didn’t help. Many other options also didn’t work, and it seems like the canvas isn’t being updated at the correct time.

How can I solve this without messing with layers? I don’t really like the idea of creating a layer for each player or something like that, and I’m not even sure if changing layers would fix anything.

internal abstract class FromOtherCamerasHider : MonoBehaviour {
    public Camera cam;

    public void Start() {
        cam = GetComponent<Camera>();
    }
    public void OnEnable() {
        RenderPipelineManager.beginFrameRendering += onBeginFrameRendering;
        RenderPipelineManager.beginCameraRendering += onBeginCameraRendering;
        RenderPipelineManager.endCameraRendering += onEndCameraRendering;
        RenderPipelineManager.endFrameRendering += onEndFrameRendering;
    }

    public void OnDisable() {
        RenderPipelineManager.beginFrameRendering -= onBeginFrameRendering;
        RenderPipelineManager.beginCameraRendering -= onBeginCameraRendering;
        RenderPipelineManager.endCameraRendering -= onEndCameraRendering;
        RenderPipelineManager.endFrameRendering -= onEndFrameRendering;
    }

    private void onBeginFrameRendering(ScriptableRenderContext context, Camera[] cameras) {
        // Debug.Log("frame begin");
        Hide();
    }
    private void onBeginCameraRendering(ScriptableRenderContext context, Camera camera) {
        if (cam == camera) {
            // Debug.Log("camera begin");
            Show();
        }
    }
    private void onEndCameraRendering(ScriptableRenderContext context, Camera camera) {
        if (cam == camera) {
            // Debug.Log("camera end");
            Hide();
        }
    }
    private void onEndFrameRendering(ScriptableRenderContext context, Camera[] cameras) {
        // Debug.Log("frame end");
        Show();
    }
    public abstract void Hide();
    public abstract void Show();
}
internal class HiderFromOtherCameras : FromOtherCamerasHider {
    public GameObject testObj;
    public override void Hide() {
        testObj.SetActive(false);
    }
    
    public override void Show() {
        testObj.SetActive(true);
    }
}

For objects like meshes and other non-UI elements, everything works fine, so this issue is not related to the code itself.

That is very much accurate, especially for overlay canvases.

If you have world space / camera space canvases the layer masks on the cameras should be able to do the job.