Search Unity

Resolved [Custom SRP] How to flip outputs for Render Texture?

Discussion in 'General Graphics' started by bitinn, Sep 7, 2020.

  1. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    For example, how do I flip context.DrawSkybox()?

    ====

    The problem: we render to a custom Render Texture instead of Built-in Render Texture (eg. CameraTarget), we need to somehow flip the unity_MatrixVP so that our skybox is not rendered up-side down.

    I am aware of an API called GL.GetGPUPorjectionMatrix(), but I am not able to inject that change to skybox pass with cmd.SetViewProjectionMatrices().

    To be honest I don't know where DrawSkybox() get its view and projection matrices. Because I can comment out context.SetupCameraProperties() and it still renders.

    ===

    Further question: Do we have to render everything upside down when using custom Render Texture, and flip the output with a final Blit()?

    - This workaround makes Frame Debugging very annoying due to flipped content, I prefer not to do so.

    Further question: I am unsure if GL.GetGPUPorjectionMatrix() is the right solution, because both DrawSkybox() and DrawGizmos() suffers from the same problem.

    ===

    Do SRP offer a solution for rendering into custom render texture?

    (I am trying to follow IsCameraProjectMatrixFlipped() in URP, but still I don't fully understand why my DrawSkybox() is flipped when I don't render into CameraTarget).
     
  2. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    For a quick reference:

    This is what I get when rendering into BuiltInRenderTextureType.CameraTarget

    srp-01.png

    This is what I get when rendering into a custom cmd.GetTemporaryRT target

    srp-02.png

    I am full aware of the Platform-specific rendering differences doc, but I do not believe this should be fixed on shader side, I believe it should be fixed on the rendering pipeline side. The problem is I don't know how.
     
  3. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    OK I am observing something very interesting:

    IF I create the render texture using GetTemporyRT directly, then result is not flipped:

    Code (CSharp):
    1. cmd.GetTemporaryRT(
    2.   colorTextureId,
    3.   width,
    4.   height,
    5.   24,
    6.   FilterMode.Point,
    7.   isHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.ARGB32,
    8.   RenderTextureReadWrite.Default,
    9.   1,
    10.   true
    11. );
    But I create the render texture using the fancy RenderTextureDescriptor:

    Code (CSharp):
    1. descriptor.colorFormat = isHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.ARGB32;
    2. descriptor.depthBufferBits = 24;
    3. descriptor.width = width;
    4. descriptor.height = height;
    5. descriptor.sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
    6. descriptor.enableRandomWrite = true;
    7. descriptor.msaaSamples = 1;
    8. descriptor.dimension = TextureDimension.Tex2D;
    9.  
    10. cmd.GetTemporaryRT(
    11.   colorTextureId,
    12.   descriptor.
    13.   FilterMode.Point
    14. );
    Looking at the code for RenderTextureDescriptor, it does automatically set a RenderTextureCreationFlags.AllowVerticalFlip that feels very suspect; but there is no way to remove it.

    Can anyone tell me why URP doesn't suffer from the same problem?
     
  4. G-Mika

    G-Mika

    Joined:
    Jul 17, 2012
    Posts:
    99
    I don't know about skyboxes (I don't use it in my custom SRP) , but when I do a fullscreen pass I need to check the builtin _ProjectionParams and invert uv.y if needed:

    Code (CSharp):
    1. if (_ProjectionParams.x > 0.0)
    2.        o.uv.y = 1.0 - o.uv.y;
     
  5. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    Thx G-Mika, I later realize my problem, I added a UNITY_UV_STARTS_AT_TOP in my shadow caster pass to flip clip space Y for testing and didn't remember to remove them.
     
  6. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    OK I am here with a final explanation on why my rendering is flipped:

    - I spoke too soon, UNITY_UV_STARTS_AT_TOP was not the problem causing my issue.

    - I double-check the new vs old GetTemporaryRT (RenderTextureDescriptor vs directly supply all parameters):

    Indeed the old syntax doesn't flip the result. While the new syntax do!

    And then I realize:

    If you set create a RenderTextureDescriptor using width and height, eg.


    Code (CSharp):
    1. var d = new RenderTextureDescriptor(0, 0);
    2. d.width = width;
    3. d.height = height;
    Then everything is fine.

    But if you do this:

    Code (CSharp):
    1. var d = new RenderTextureDescriptor();
    2. d.width = width;
    3. d.height = height;
    Then the result will be flipped.

    Holy moly, be careful when you init and reuse a large struct.
     
    c0d3_m0nk3y, Just_Lukas and Babiole like this.
  7. Just_Lukas

    Just_Lukas

    Joined:
    Feb 9, 2019
    Posts:
    34
    What a find! Unity's flipped rendering has been torturing me for hours and thanks to you I've figured it out and here's why:

    When creating RenderTextureDescriptor with its default constructor the flags field will not have value of AllowVerticalFlip but when creating descriptor using specific constructors then this flag will be set and rendering is corrected.

    Code (CSharp):
    1.  
    2.         public RenderTextureDescriptor(int width, int height, GraphicsFormat colorFormat, int depthBufferBits, int mipCount)
    3.         {
    4.             this = default(RenderTextureDescriptor);
    5.              // Below the correct flag "AllowVerticalFlip" is set
    6.             _flags = RenderTextureCreationFlags.AutoGenerateMips | RenderTextureCreationFlags.AllowVerticalFlip;
    7.             this.width = width;
    8.             this.height = height;
    9.             volumeDepth = 1;
    10.             msaaSamples = 1;
    11.             graphicsFormat = colorFormat;
    12.             depthStencilFormat = RenderTexture.GetDepthStencilFormatLegacy(depthBufferBits, colorFormat);
    13.             this.mipCount = mipCount;
    14.             dimension = TextureDimension.Tex2D;
    15.             shadowSamplingMode = ShadowSamplingMode.None;
    16.             vrUsage = VRTextureUsage.None;
    17.             memoryless = RenderTextureMemoryless.None;
    18.         }