Is there a way to render a UI canvas into a buffer or RenderTexture?

I’m attempting an offset ghosting effect for some of the UI in our game.

Since the “effect” is larger than the bounding box of the UI elements I want to ghost, and because I have mixed elements that use different shaders (image background + TMPro text), my naive solution is to render out a subcanvas or group of UI elements into a buffer that’s slightly larger than the bounding box and then run a post-process effect on it, blitting it back to the screen.

I’m just not sure if there’s a good way to accomplish that.

1 Like

you can easily render the ui into a render texture by changing the Render Mode of the canvas to “Screen Space - Camera”.
Since you need to render more than the canvas itself this might not work for you perfectly. But you can also set it to “World Space”. Now you can place the UI wherever you want and render with a camera as much as you need.

1 Like

This will open a can of worms if the render texture size doesn’t match the camera’s resolution (i.e. for rendering at a bit lower or a bit higher resolution).

  • The UI sizing will be scaled different (unless a custom made component that inherits from CanvasScaler and handles the HandleScaleWithScreenSize() method.
  • Buttons, raycasts and others don’t seem to work (I’m still trying to find a solution for this).
1 Like

Did you find a solution to this?

Not at the time and I can’t remember what I did with it. Probably just kept it full screen res (a render target that gets created dynamically depending on back buffer sizes on start).

The only dynamic render target resolution handling that I did and kept afterwards is for screen rays from the pointer like so:

// Has a render texture, so handle via viewport coords.

Camera c;

var viewportCoord = new Vector3()
{
    x = position.x / Screen.width,
    y = position.y / Screen.height,
    z = c.nearClipPlane
};
var r = c.ViewportPointToRay(viewportCoord);
return r;

// Caveats
// On editor the Screen class's width/height is the monitor's device resolution and not the game view. This works as a workaround:
#if UNITY_EDITOR
    string[] resWidthAndHeight = UnityEditor.UnityStats.screenRes.Split('x');

    width = System.Convert.ToInt32(resWidthAndHeight[0]);
    height = System.Convert.ToInt32(resWidthAndHeight[1]);

    //Debug.Log("Size: " + UnityEditor.UnityStats.screenRes);
#endif

For UI didn’t find a similar solution to tweak the ray, pointer, etc positions.