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 are updating our Terms of Service for all Unity subscription plans, effective October 13, 2022, to create a more streamlined, user-friendly set of terms. Please review them here: unity.com/legal/terms-of-service.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

Question Encoding to png gives very dark results

Discussion in 'General Graphics' started by gwelkind, Aug 13, 2022.

  1. gwelkind

    gwelkind

    Joined:
    Sep 16, 2015
    Posts:
    57
    Within the editor, I'm trying to instantiate a Camera, capture it's frame to a premade render texture, blit these onto a temporary texture, then send bytes from the temporary texture to a png file. Ultimately, I'm trying to get a specialized screenshot of objects when I press a certian button in edit mode. Using Unity 2021.3.6f1 fwiw

    Where I'm running into issues seems to be when I actually call `tex.EncodeToPNG()`

    The reason I believe this is that I'm storing the intermediate texture as a public serialized variable, and inspecting it, and it looks OK. The png produced is really really dark, though colors are still distinguishable.

    I've included pictures of the produced png and the intermediate texture.

    I've tried using several other graphics formats for my render texture (while keeping them in sync to the Texture2D), none of them seem to make a difference.


    Code (CSharp):
    1.        
    2. var projectionCameraGO = Instantiate(Resources.Load<GameObject>("DetailProjectionCamera"));
    3.         projectionCameraGO.transform.position = transform.position - projectionCameraGO.transform.forward * 10f;
    4.         var projectionCamera = projectionCameraGO.GetComponent<Camera>();
    5.  
    6.         var gfxFormat = GraphicsFormat.R8G8B8A8_UNorm;
    7.         var rTex = projectionCamera.targetTexture;
    8.         projectionCamera.orthographicSize = rTex.height / 2f / 16f;
    9.         TextureCreationFlags flags = TextureCreationFlags.None;
    10.  
    11.         Texture2D tex = new Texture2D(rTex.width, rTex.height, gfxFormat, flags);
    12.         RenderTexture.active = rTex;
    13.         tex.ReadPixels(new Rect(0, 0, rTex.width, rTex.height), 0, 0);
    14.         tex.Apply();
    15.      
    16.         tmpTestTexture = tex;
    17.         byte[] bytes = tex.EncodeToPNG();
    18.         System.IO.File.WriteAllBytes(Application.dataPath + "/" + gameObject.name + "_projection.png", bytes);
    19.  
    20.  

    Thanks very much in advance for your help
     

    Attached Files:

  2. gwelkind

    gwelkind

    Joined:
    Sep 16, 2015
    Posts:
    57
    I suspect this has to do with colorspace/sRGB, but MAN does Unity make this hard to understand.

    There's RenderTextureFormat, DefaultFormat, GraphicsFormat and TextureFormat, all of which contain enum names which aren't consistent or clearly intercompatible.

    It seems to enforce RenderTexture as sRGB space, I'd have to use this constructor https://docs.unity3d.com/ScriptReference/RenderTexture-ctor.html

    but it's not at all clear to me which RenderTextureFormat I should use and how to build a Texture2D which is compatible with my selected RenderTextureFormat... Why can't these just share one enum???
     
  3. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,224
    RenderTextures are objects that live in GPU video memory. They are not compressed and cannot be serialized to disk. Texture2D however lives in CPU memory and can be compressed, so they have a very different set of formats available. These are what RenderTextureFormat and TextureFormat are, respectively.

    DefaultFormat returns the default platform format for a specific kind of texture content (HDR, LDR, stencil, depth, etc).

    GraphicsFormat is relatively new, and I suspect it's supposed to eventually replace both RenderTextureFormat and TextureFormat.

    Your graphics format is GraphicsFormat.R8G8B8A8_UNorm, which is a normalized format with 8 bit precision for each channel. Instead of using this to create your Texture2D, try using rTex.graphicsFormat.
     
    Torbach78 likes this.
  4. gwelkind

    gwelkind

    Joined:
    Sep 16, 2015
    Posts:
    57
    This is extremely helpful for my understanding. In the end, I needed to use sRGB for both in order to get this to work.

    Thank you very much for this response, I couldn't find a decent explanation of it anywhere and you outlined it with perfect clarity.
     
unityunity