UI Scaling when Off-Screen Rendering

Hi there. I’m the author of NatCorder, a video recording API for Unity. Ever since upgrading from Unity 2019.4.5 to 2019.4.18, I’ve stumbled upon a bug in the UI system that wasn’t there before:

I’m using a canvas scaler on a UI canvas that’s set to ‘screen space - camera’, allowing it to be rendered to texture. I have a reference resolution set to some high resolution (currently, 1440x2560) but in code, I’m rendering the game camera to a texture that is (720x1280). Note that because the aspect ratios are the same, and because the canvas scaler is set to match width or height evenly (0.5 on the slider), the canvas scaler should be doing a linear down-scaling. Heres how it looks in editor:


But when I render it to texture using the following code:

// Render the screen
var reTex = RenderTexture.GetTemporary(720, 1280, 24);
uiCamera.targetTexture = reTex;
uiCamera.Render();
uiCamera.targetTexture = null;
// Write out
var tex2D = new Texture2D(reTex.width, reTex.height);
RenderTexture.active = reTex;
tex2D.ReadPixels(new Rect(0, 0, tex2D.width, tex2D.height), 0, 0);
var jpgData = tex2D.EncodeToJPG();
var path = Path.Combine(Directory.GetCurrentDirectory(), "screenshot.jpg");
File.WriteAllBytes(path, jpgData);

The screenshot comes out like so:


I’ve tracked the problem down to this line in CanvasScaler:: HandleScaleWithScreenSize:

Vector2 screenSize = new Vector2(Screen.width, Screen.height);

I’m not sure what might have changed, because before this was never an issue. The fix is simple enough, something like the following:

var screenSize = Camera.current.targetTexture ?
            new Vector2(Camera.current.targetTexture.width, Camera.current.targetTexture.height) :
            new Vector2(Screen.width, Screen.height);

Which produces the expected:


But this is only a partial fix. The other half, so to speak, is listening to Camera.onPreCull and re-calculating the scale factor each time it’s called. The problem is that I can’t get this to work for some reason. Instead, I have to explicitly have HandleScaleWithScreenSize called before I call Camera::Render. Any ideas?

1 Like

Bump!

Bump bump!

It seems that this is a known issue, and has been known for quite some time .

I guess it is already fixed?
https://issuetracker.unity3d.com/issues/ugui-in-texture2d-is-different-than-in-the-game-view-when-calling-totexture2d-method-on-a-rendertexture

Just checked, you’re right. It has indeed been fixed. Thank you so much!