Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Resolved RenderTexture not clearing buffer on Android

Discussion in 'General Graphics' started by Garmichael, Dec 17, 2022.

  1. Garmichael

    Garmichael

    Joined:
    Mar 17, 2013
    Posts:
    17
    I have a system where there's no main camera. Instead, each layer of the game (tiles, characters, huds, etc) has its own camera and is rendering to a RenderTexture. Then I use the OnGUI method to draw each layer with DrawTexture one on top of each other. It works fine when building for pc, but the android build refuses to clear the buffer each frame, resulting in the attached image.

    Here is the relevant code:

    Setting up the Camera and RenderTexture:
    Code (CSharp):
    1. private RenderTexture BuildRenderTexture() {
    2.     RenderTexture = new RenderTexture(
    3.         GameProperties.RenderDimensionsWidth,
    4.         GameProperties.RenderDimensionsHeight,
    5.         24,
    6.         RenderTextureFormat.Default
    7.     ) {filterMode = FilterMode.Point};
    8.     RenderTexture.Create();
    9.  
    10.     Camera = gameObject.AddComponent<UnityEngine.Camera>();
    11.     Camera.clearFlags = CameraClearFlags.Color;
    12.     Camera.backgroundColor = new Color(0, 0, 0, 0);
    13.     Camera.cullingMask = -1;
    14.     Camera.orthographic = true;
    15.     Camera.nearClipPlane = 0f;
    16.     Camera.farClipPlane = GameProperties.MapLayerDepth;
    17.     Camera.depth = 1f;
    18.     Camera.targetDisplay = 0;
    19.     Camera.aspect = GameProperties.AspectRatio;
    20.     Camera.orthographicSize = GameProperties.DefaultCameraSize;
    21.     Camera.targetTexture = RenderTexture;
    22.  
    23.     VisibleTileCount = new Vector2(
    24.         Camera.orthographicSize * 2f * Camera.aspect,
    25.         Camera.orthographicSize * 2f
    26.     );
    27.  
    28.     return RenderTexture;
    29. }
    Using OnGUI to render each RenderTexture to the screen:
    Code (CSharp):
    1. private void OnGUI() {
    2.     RenderBackdrop();
    3.  
    4.     GUI.BeginGroup(new Rect(0, 0, Screen.width, Screen.height));
    5.     foreach (KeyValuePair<string, MapCameraLayer> mapCameraLayer in _mapCameraLayers) {
    6.         RenderLayer(mapCameraLayer.Value.RenderTexture);
    7.     }
    8.  
    9.     foreach (KeyValuePair<string, RenderTexture> uiCameraLayer in _uiCameraLayers) {
    10.         RenderLayer(uiCameraLayer.Value);
    11.     }
    12.  
    13.     GUI.EndGroup();
    14. }
    15.  
    16. private void RenderBackdrop() {
    17.     Graphics.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), _backdrop);
    18. }
    19.  
    20. private void RenderLayer(RenderTexture renderTexture) {
    21.     Rect screenRenderRect = GetRenderRect();
    22.     Graphics.DrawTexture(screenRenderRect, renderTexture);
    23. }
    I have no idea if this issue is a problem with the Camera, the RenderTexture, the Android Player Build Settings, or with Unity itself.
     

    Attached Files:

  2. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
    I believe the default `DrawTexture` material that is used in `RenderBackdrop` enabled alpha blending. Maybe the result is blending on top of an uninitialized framebuffer. Or are you sure that `_backdrop` has all opaque alpha channel.

    I would recommend to add a main camera that clears color and depth of the main framebuffer or use the immediate clear API (GL.Clear) before your compositing step.
     
    Garmichael likes this.
  3. Garmichael

    Garmichael

    Joined:
    Mar 17, 2013
    Posts:
    17
    _backdrop is created as:

    Code (CSharp):
    1. private void BuildBackdropTexture() {
    2.     Color32[] backdropColor = {Color.black};
    3.     _backdrop = new Texture2D(1, 1);
    4.     _backdrop.SetPixels32(backdropColor);
    5.     _backdrop.Apply();
    6. }
    It looks like this could just be replaced with
    GL.Clear(true, true, Color.black)


    I added the clear command as the first line in OnGUI, and this doesn't resolve the problem. I also added a main camera (which OnGUI just draws over the top of anyway) and this also didnt resolve the problem.





    To be more clear about what's going on, let me show in images.

    The scene in 3d looks like this:



    You can see two cameras: both facing in the same direction and only capturing whats inside the white box in front of it. One captures the bit with the room and the door. The other captures the bit with the player and the tables. Both cameras have their ClearFlags set to Color (per the construction code I posted in the first post of this thread).

    The camera settings are:


    The cameras pick up the following:

    First one


    Second one




    So we first draw a black texture (or GL.Clear. or both.) to the whole screen. Then render the first RenderTexture(the door/room) on top of that backdrop, and then render the second RenderTexture (the player and tables) on top of those. To result in:



    And it works perfectly, except on Android, where the RenderTexture's buffer isnt being cleared.


    This is a critical bug for my asset that's currently available on the store, and I've tried everything I can think of, and I'm getting the same result every time.
     
  4. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
    Not sure what's causing this.
    A common issue that people run into is that framebuffer content is undefined at the beginning of a frame and on Android this often gives different results compared to other platforms. This doesn't seem to be the case here.

    Have you tried to look at the individual render textures in Unity's frame debugger and RenderDoc?
     
    Garmichael likes this.
  5. Garmichael

    Garmichael

    Joined:
    Mar 17, 2013
    Posts:
    17
    I finally figured out the problem and I'm posting here in case anyone else runs into it. I was using
    Graphics.Blit(RenderTexture, RenderTexture, _material);
    in
    OnPostRender()
    . I changed it so that I am now applying the material in
    Graphics.DrawTexture
    and that works.