Search Unity

Discussion How to efficiently extract a render texture from the Built-In render pipeline?

Discussion in 'General Graphics' started by _geo__, May 10, 2023.

  1. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,345
    Hi all,
    this is more a question about whether I am doing this right.
    It's working but I do worry about efficiency.

    So, I have implemented an OnPreRender() and an OnPrenderImage(src, dest) method to get access to the image before any UI is rendered. What I want is to copy the "src" render texture to another (much smaller) render texture which I then apply some effect on and use elsewhere (I show it in the UI to emulate some translucency effects).

    It works fine, yet I am not 100% sure this is the best way to do it.

    Here is the gist of the code:
    Code (CSharp):
    1. Material MaterialWithSomeEffect;
    2. RenderTexture MyRenderTextureThatIsUsedElsewhere;
    3. RenderTexture _rt;
    4.  
    5. void OnPreRender()
    6. {
    7.     // This is done due to an ancient (2016) Unity forum thread which mentions that
    8.     // if no render texture is assigned Unity will copy the texture pixel by pixel (which is slow).
    9.     // See: https://forum.unity.com/threads/post-process-mobile-performance-alternatives-
    10.     //      to-graphics-blit-onrenderimage.414399/#post-2759255
    11.     // Q: Is this still necessary?
    12.     _rt = RenderTexture.GetTemporary(Screen.width, Screen.height, 16);
    13.     Camera.main.targetTexture = _rt;
    14. }
    15.  
    16. void OnRenderImage(RenderTexture src, RenderTexture dest)
    17. {
    18.     // See on PreRender
    19.     Camera.main.targetTexture = null;
    20.     RenderTexture.ReleaseTemporary(_rt);
    21.  
    22.     // Bascially all I need is a copy of src.
    23.     Graphics.Blit(src, MyRenderTextureThatIsUsedElsewhere, MaterialWithSomeEffect);
    24.  
    25.     // Since we did render into a render texture (see OnPreRender) we now
    26.     // have to blit the contents to the frame buffer.
    27.     // Q: Is that correct?
    28.     Graphics.Blit(src, null as RenderTexture);
    29.  
    30.     // Otherwise we will get a "OnRenderImage() possibly didn't write anything
    31.     // to the destination texture!" warning.
    32.     Graphics.Blit(src, dest);
    33. }
    It looks okay in the frame debugger, but I wonder if maybe the final "Graphics.Blit(src, dest)" can be axed or somehow merged with the "Graphics.Blit(src, null as RenderTexture)".

    It seems inefficient to do the same blit twice. I tried Graphics.CopyTexture() instead of the final blit, yet then I get a "Graphics.CopyTexture can only copy between same texture format groups (d3d11 base formats: src=9 dst=27)" error.

    Anyways, thanks for reading it all :)
    Here is the link that's mentioned in the comments.