Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug UI Scaling when Off-Screen Rendering

Discussion in 'UGUI & TextMesh Pro' started by Lanre, Mar 8, 2021.

  1. Lanre

    Lanre

    Joined:
    Dec 26, 2013
    Posts:
    3,967
    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:
    Screen Shot 2021-03-07 at 20.17.42.png
    But when I render it to texture using the following code:
    Code (CSharp):
    1. // Render the screen
    2. var reTex = RenderTexture.GetTemporary(720, 1280, 24);
    3. uiCamera.targetTexture = reTex;
    4. uiCamera.Render();
    5. uiCamera.targetTexture = null;
    6. // Write out
    7. var tex2D = new Texture2D(reTex.width, reTex.height);
    8. RenderTexture.active = reTex;
    9. tex2D.ReadPixels(new Rect(0, 0, tex2D.width, tex2D.height), 0, 0);
    10. var jpgData = tex2D.EncodeToJPG();
    11. var path = Path.Combine(Directory.GetCurrentDirectory(), "screenshot.jpg");
    12. File.WriteAllBytes(path, jpgData);
    The screenshot comes out like so:
    no_scaler.jpg
    I've tracked the problem down to this line in `CanvasScaler::
    HandleScaleWithScreenSize`:
    Code (CSharp):
    1. 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:
    Code (CSharp):
    1. var screenSize = Camera.current.targetTexture ?
    2.             new Vector2(Camera.current.targetTexture.width, Camera.current.targetTexture.height) :
    3.             new Vector2(Screen.width, Screen.height);
    Which produces the expected:
    custom.jpg
    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?
     
    TillmaniaLtd likes this.
  2. Lanre

    Lanre

    Joined:
    Dec 26, 2013
    Posts:
    3,967
    Bump!
     
  3. Lanre

    Lanre

    Joined:
    Dec 26, 2013
    Posts:
    3,967
  4. Lanre

    Lanre

    Joined:
    Dec 26, 2013
    Posts:
    3,967