Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Converting texture2d array to a different pixel format (R8 to RGBA32)

Discussion in 'General Graphics' started by erikwp, Apr 3, 2018.

  1. erikwp

    erikwp

    Joined:
    Jan 16, 2018
    Posts:
    25
    Hi I'm hoping to get some help on this problem I'm stuck on. I have a Texture2D that is R8 pixel format (one channel) and I need to convert it to a Color32[] array. Does anyone know how to do it?

    I create the two textures like this:
    Code (CSharp):
    1. Texture2D arCamTex2d_R8pixelFormat = YUVMaterial.GetTexture("_textureY") as Texture2D;
    2. Texture2D tex32 = new Texture2D(arCamTex2d_R8pixelFormat.width, arCamTex2d_R8pixelFormat.height, TextureFormat.RGBA32, false);
    And then I tried to simply set the pixels like so:
    Code (CSharp):
    1. tex32.SetPixels(arCamTex2d_R8pixelFormat.GetPixels());
    2. tex32.Apply();
    But this does not work and tex32 is blank. So I tried to load the raw bytes like so:
    Code (CSharp):
    1. tex32.LoadRawTextureData(arCamTex2d_R8pixelFormat.GetRawTextureData());
    2. tex32.Apply();
    3. //preview texture onto a quad
    4. quad.GetComponent<Renderer>().material.mainTexture = tex32 as Texture;
    But this also does not work. What is the correct way to do this? Any help is much appreciated. Thanks
     
  2. alany07

    alany07

    Joined:
    Oct 16, 2018
    Posts:
    2
    Hi Ericparr,

    I ran into the same issue. Did you figure it out? Appreicate if you can share the solution. Thanks, -Alan
     
  3. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    R8 is a 8-bit integer number of a 0-255 range (a byte) to describe every pixel. RGBA32 is 4 bytes, byte for every channel/letter (4 * 8 bits = 32 bits, hence the name).

    Code (CSharp):
    1. byte[] pixelsR8 = textureR8.GetRawTextureData();
    2. Color32[] pixelsRGBA32 = new Color32[ pixelsR8.Length ];
    3. for( int i=pixelsR8.Length-1 ; i!=-1 ; i-- )
    4. {
    5.     byte value = pixelsR8[i];
    6.     pixelsRGBA32[i] = new Color32( value , value , value , 255 );//simplest R8 to RGBA32 conversion
    7. }
    8. textureRGBA32.SetPixels32( pixelsRGBA32 );//updates textureRGBA32 data in CPU memory
    9. textureRGBA32.Apply();//sends textureRGBA32 data from CPU memory to GPU (without this rendering wont change a bit)
    Would you like to know more?
     
    Last edited: Sep 1, 2022
    Nekono10 and cor3genz like this.
  4. LogicFlow

    LogicFlow

    Joined:
    Aug 18, 2018
    Posts:
    33
    If RGBA32 out is what you want, the above works great, but I provide a more performant alternative here. The point of using 1 byte per channel is to keep things small and fast. In an ideal world, you'd expand the single channel into multiple channels in a shader. This reduces the amount of data sent across the system bus by 4x. To see this work, use one of the Unlit/ shaders which will accept the single channel to display output in red only.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class TestRawTextureData : MonoBehaviour
    4. {
    5.     public Renderer renderer = null;
    6.     Texture2D texture = null;
    7.  
    8.     const int WIDTH = 8192; //NOTE: hard to see, reduce to 256 for easier visual.
    9.     byte[] data = new byte[WIDTH * WIDTH];
    10.  
    11.     int texelIndex = 0;
    12.  
    13.     void Start()
    14.     {
    15.         texture = new Texture2D(WIDTH, WIDTH, TextureFormat.R8, false);
    16.         texture.filterMode  = FilterMode.Point;
    17.         texture.LoadRawTextureData(data);
    18.         texture.Apply();
    19.  
    20.         renderer.material.mainTexture = texture;
    21.     }
    22.  
    23.     void Update()
    24.     {
    25.         var rawData = texture.GetRawTextureData<byte>();
    26.         rawData[texelIndex] = (byte)255;
    27.         //or set 2-bytes per texture element such as TextureFormat.RG16 using:
    28.         //rawData[ [i * 2 + 0] = 128;
    29.         //rawData[ [i * 2 + 1] = 255;
    30.         texelIndex++;
    31.         texture.Apply();
    32.     }
    33. }
    34.  
     
    Last edited: Aug 31, 2022