Search Unity

Question Offscreen rendering

Discussion in 'General Graphics' started by stylophone, May 17, 2020.

  1. stylophone

    stylophone

    Joined:
    Aug 16, 2012
    Posts:
    37
    Hi, I'm trying to achieve an offscreen rendering implementation for my project. The progress is ok I can actually render something without showing it on the screen nor wait for the renderer life circle. The problem is, after the render has finished, Unity took a long time break (freeze) before start rendering the next frame. Even the offscreen rendering process has taken for only 348ms, but Unity will be freezing for somewhere between 5-6 secs before the next frame start rendering in my case. I understand that is probably because I'm still done stuff in the rendering life circle and Unity probably has to be sync with the main thread or for some reason. But it's there any way I can prevent the break? Or perhaps there's a better practice for my case? Here's code:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [RequireComponent(typeof(Camera))]
    4. public class OffscreenRendering : MonoBehaviour
    5. {
    6.     public int maxFrame = 120;
    7.     public bool render;
    8.     public Material material;
    9.     public Animator animator;
    10.     public SkinnedMeshRenderer[] skinnedMeshRenderers;
    11.  
    12.     public void OnRenderImage(RenderTexture source, RenderTexture destination)
    13.     {
    14.         if (render)
    15.         {
    16.             float startTime = Time.realtimeSinceStartup;
    17.             Debug.Log("Start render at: " + startTime);
    18.  
    19.             RenderTexture rt = new RenderTexture(source);
    20.             Mesh mesh = new Mesh();
    21.  
    22.             for (int i = 0; i < maxFrame; i++)
    23.             {
    24.                 rt.Create();
    25.                 Graphics.SetRenderTarget(rt);
    26.                 Graphics.Blit(source, rt);
    27.  
    28.                 animator.Update(1.0f / Application.targetFrameRate);
    29.                 material.SetPass(0);
    30.  
    31.                 for (int j = 0; j < skinnedMeshRenderers.Length; j++)
    32.                 {
    33.                     skinnedMeshRenderers[j].BakeMesh(mesh);
    34.                     Graphics.DrawMeshNow(mesh, Vector3.left, Quaternion.identity);
    35.                 }
    36.  
    37.                 //MeshBlit.SaveFrame(rt, i + ".png"); Save the frame on disk.
    38.  
    39.                 Graphics.SetRenderTarget(null);
    40.                 rt.Release();
    41.             }
    42.  
    43.             Debug.LogFormat("Render finished at: {0}, span: {1}", Time.realtimeSinceStartup, Time.realtimeSinceStartup - startTime);
    44.             render = false;
    45.         }
    46.  
    47.         Graphics.SetRenderTarget(source);
    48.         Graphics.Blit(source, destination);
    49.     }
    50. }
    upload_2020-5-17_22-22-58.png
     
  2. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    The problem is you are creating a new RenderTexture and Mesh on every frame. Move the creation of those two to OnStart() and hold onto them in class fields.
     
  3. stylophone

    stylophone

    Joined:
    Aug 16, 2012
    Posts:
    37
    Thanks for the reply. Yes frequently calling the create/release of RenderTexture is exactly why that editor got freeze. Here's the code I finally have done in case anyone wants to use it:

    Code (CSharp):
    1.  
    2.     Debug.Log("Start render at: " + Time.realtimeSinceStartup);
    3.  
    4.     RenderTexture rt = new RenderTexture(source);
    5.     rt.format = RenderTextureFormat.ARGB32; // Here we use ARGB32 in case the source is a HDR format or something else...that would be diffcult to catch with AsyncGPUReadback
    6.     rt.Create();
    7.  
    8.     Graphics.SetRenderTarget(rt);
    9.     TextureSaver textureSaver = new TextureSaver(rt.graphicsFormat, rt.width, rt.height, Application.persistentDataPath);
    10.  
    11.     Mesh mesh = new Mesh();
    12.  
    13.     for (int i = 0; i < maxFrame; i++)
    14.     {
    15.         GL.Clear(true, false, Color.black);
    16.         Graphics.Blit(source, rt);
    17.  
    18.         animator.Update(1.0f / Application.targetFrameRate);
    19.         material.SetPass(0);
    20.  
    21.         for (int j = 0; j < skinnedMeshRenderers.Length; j++)
    22.         {
    23.             skinnedMeshRenderers[j].BakeMesh(mesh);
    24.             Graphics.DrawMeshNow(mesh, Vector3.left, Quaternion.identity);
    25.         }
    26.  
    27.         AsyncGPUReadback.Request(rt, 0, rt.graphicsFormat, (obj) =>
    28.         {
    29.             NativeArray<Color32> buffer = obj.GetData<Color32>();
    30.             textureSaver.Queue(buffer.ToArray());
    31.         });
    32.     }
    33.  
    34.     Debug.Log("Render finished at: " + Time.realtimeSinceStartup);
    35.  
    Result:
     
    Circool and Neto_Kokku like this.