Search Unity

Render to texture problem on Android 5.x devices

Discussion in 'General Graphics' started by glad, May 21, 2019.

  1. glad

    glad

    Joined:
    May 10, 2014
    Posts:
    76
    Hi!

    I do something like screenshots of some elements of game during runtime. So I use render to texture. I create temporary camera, focus it on the object, render it to texture and then delete camera returning created texture.

    Here is how I do that(render to texture part):

    Code (CSharp):
    1.  // ...
    2. int width = (int)Camera.main.WorldToScreenPoint(bounds.size).x - Screen.width /2;
    3.             RenderTexture renderTexture = RenderTexture.GetTemporary(256, 256, 32);
    4.             renderTexture.Create();
    5.             texCamera.targetTexture = renderTexture;
    6.  
    7.             Texture2D screenShot = new Texture2D(256, 256, TextureFormat.ARGB32,false);
    8.             texCamera.Render();
    9.             RenderTexture.active = renderTexture;
    10.             //screenShot.ReadPixels(new Rect(0, 0, 256, 256), 0, 0);
    11.             Graphics.CopyTexture(renderTexture, screenShot);
    12.             //screenShot.Apply();
    13.             texCamera.targetTexture = null;
    14.             RenderTexture.active = null;
    15.             // ...
    16.  
    after I get Texture2D I create sprite and do something like: Image.sprite = createdSprite;

    Nothing special.. It is working on most devices, however it is not on Android 5.02. I see grey square instead of picture.

    Tested on 2018.2.3f1 and on 2018.4.0f1

    If anyone could help - thank you!
     
  2. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    Here are some things to try:
    • You have specified ARGB32 as you format, but you device may actually render to a 16 buffer by default. Check if setting "Use 32-bit Display Buffer" helps you https://docs.unity3d.com/Manual/class-PlayerSettingsAndroid.html
    • Your device may not support the texture format you specified, or otherwise messes up the rendering because of the mismatch. Try using the texture format obtained from the device instead of hardcoding it.
    • Try using Blit and getTemporary instead of your current setup? This one is a bit of a stretch, but as far as efficiency goes I was told getTemporary is preferable performance-wise.
     
  3. glad

    glad

    Joined:
    May 10, 2014
    Posts:
    76
    @BakeMyCake Thank you for your help.

    1. Use 32-bit Display Buffer is checked. So there is no problem with that
    2. > Try using the texture format obtained from the device instead of hardcoding it.
    Could you please tell how can I do that ?

    I use GetTemporary as you may see. Here is a full source:

    Code (CSharp):
    1. public static Texture2D MakePreview(GameObject go, string exceptTag)
    2.         {
    3.             // 1. Instantiate
    4.             //GameObject go = GameObject.Instantiate(prefab);
    5.             go.transform.position = new Vector3(-500, 0, 0);
    6.  
    7.             // 2. Getting bounds
    8.             Bounds bounds = GetBoundsForObject(go, exceptTag);
    9.  
    10.             // 3. Init camera
    11.             GameObject cameraGo = new GameObject("TextureCamera");
    12.             Camera texCamera = cameraGo.AddComponent<Camera>();
    13.             texCamera.orthographic = true;
    14.             Vector3 cameraPos = go.transform.position;
    15.             cameraPos.z = -1;
    16.             //texCamera.transform.position = cameraPos;
    17.             texCamera.transform.position = new Vector3(bounds.center.x, cameraPos.y, cameraPos.z);
    18.  
    19.             // 4. Adjusting camera with bounds
    20.             float ratio = Screen.width / Screen.height;
    21.             float objectBoundsRatio = bounds.size.x / bounds.size.y;
    22.             float orthographicSize = 0.0f;
    23.             //if (objectBoundsRatio >= 1.0f)
    24.             {
    25.                 //orthographicSize = bounds.size.x / (2 * ratio);
    26.             }
    27.             //else
    28.             //{
    29.                 orthographicSize = bounds.size.x / 2.0f;
    30.             //}
    31.  
    32.  
    33.             texCamera.orthographicSize = orthographicSize;
    34.  
    35.             // 5. Creating a renderTexture and rendering to it
    36.             //RenderTexture renderTexture = new RenderTexture(256, 256, 32, RenderTextureFormat.ARGB32);
    37.             int width = (int)Camera.main.WorldToScreenPoint(bounds.size).x - Screen.width /2;
    38.             RenderTexture renderTexture = RenderTexture.GetTemporary(256, 256, 32);
    39.             renderTexture.Create();
    40.             texCamera.targetTexture = renderTexture;
    41.  
    42.             Texture2D screenShot = new Texture2D(256, 256, TextureFormat.ARGB32,false);
    43.             texCamera.Render();
    44.             RenderTexture.active = renderTexture;
    45.             //screenShot.ReadPixels(new Rect(0, 0, 256, 256), 0, 0);
    46.             Graphics.CopyTexture(renderTexture, screenShot);
    47.             //screenShot.Apply();
    48.             texCamera.targetTexture = null;
    49.             RenderTexture.active = null; // JC: added to avoid errors
    50.  
    51.             screenShot.name = go.name;
    52.  
    53.             GameObject.DestroyImmediate(go);
    54.             GameObject.DestroyImmediate(texCamera.gameObject);
    55.      
    56.             RenderTexture.ReleaseTemporary(renderTexture);
    57.  
    58.             return screenShot;
    59.         }
    60.  
    61.         private static string GetScreenshotName(string baseName, int resX, int resY)
    62.         {
    63.             return baseName + "_" + resX + "x" + resY + ".png";
    64.         }
    65.  
    66.         public static Bounds GetBoundsForObject(GameObject prefab, string exceptTag)
    67.         {
    68.             Transform rootTransform = prefab.transform;
    69.             Vector3 tmpSize = Vector3.zero;
    70.  
    71.             Bounds ret = new Bounds();
    72.             SpriteRenderer[] srList = prefab.GetComponentsInChildren<SpriteRenderer>();
    73.             for (int i = 0; i < srList.Length; ++i)
    74.             {
    75.                 if (srList[i].gameObject.CompareTag(exceptTag))
    76.                     continue;
    77.                 else
    78.                 {
    79.                     var elem = srList[i];
    80.                     if (i == 0)
    81.                         ret = elem.bounds;
    82.                     else
    83.                         ret = CombineBounds(ret, elem.bounds);
    84.                 }
    85.             }
    86.  
    87.             return ret;
    88.         }
    89.  
    90.         private static Bounds CombineBounds(Bounds b1, Bounds b2)
    91.         {
    92.             Bounds result = new Bounds();
    93.  
    94.             Vector2 min = new Vector2(Mathf.Min(b1.min.x, b2.min.x), Mathf.Min(b1.min.y, b2.min.y));
    95.             Vector2 max = new Vector2(Mathf.Max(b1.max.x, b2.max.x), Mathf.Max(b1.max.y, b2.max.y));
    96.  
    97.             result.min = min;
    98.             result.max = max;
    99.  
    100.             return result;
    101.         }
    And then I do:

    Code (CSharp):
    1. Texture2D previewTexture = Utils.PreviewMaker.MakePreview(instantiatedPrefab, GameConstants.TagDoNotTakeScreenshot);
    2.                         img.sprite = Sprite.Create(previewTexture, new Rect(0, 0, previewTexture.width, previewTexture.height), new Vector2(0.5f, 0.5f), 100, 1, SpriteMeshType.FullRect);
     
  4. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    You can obtain it using this https://docs.unity3d.com/ScriptReference/RenderTextureFormat.Default.html

    My bad.

    I stumbled upon multiple unitydocs pages showing how to capture camera into a texture:
    https://docs.unity3d.com/ScriptReference/RenderTexture-active.html
    https://docs.unity3d.com/ScriptReference/Camera.Render.html
    If you make a clean project and use the code from those links does it work on your targed device? If it does maybe you could incorporate that into your project.
     
    sfilo likes this.