Search Unity

reading an RGB32 pixel

Discussion in 'Shaders' started by lclemens, Jan 9, 2021.

  1. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    760
    I'm having trouble understanding the numbers that come back from tex2Dlod() in a vertex shader.

    At first I was using textures that were allocated with ARGBHalf to store vertex positions. So for example, to fetch the second pixel in the first row I did something like this:

    Code (CSharp):
    1. int x = 1;
    2. int y = 0;
    3. float4 values = tex2Dlod(_PosTex, float4((x + 0.5) * _PosTex.x, (y+ 0.5) * _PosTex.y, 0, 0)
    Everything worked perfectly fine with ARGBHalf buffers. Then I decided to try it with ARGB32 instead, and suddenly the return values of tex2Dlod() are gibberish.

    Let's say I set the RGBA values of pixel location (1,0) in the texture to rgba(8, 51, 11, 0). When I set them, I divided each 8-bit component by 255 to convert them to a number between 0 and 1 so that the numbers I actually wrote to the texture were (0.0313725, 0.2, 0.04313725, 0). When I export the texture to png and then open it with Glimpse I see:
    upload_2021-1-8_15-26-30.png
    (The shader reads the pixels starting in the bottom left, so the pixel under consideration is in the bottom left of the png image).
    So far so good. The values appear as I would have expected... (8, 51, 11, 0)... the exact numbers I stored at that location.

    Just to double-check, I captured a frame in RenderDoc and examined the texture there:
    upload_2021-1-8_15-30-22.png

    Here the values don't make sense. It's showing an rgba value of (0.00244, 0.0332, 0.00336, 0). I expected to see (8 / 255, 51 / 255, 11 / 255, 0), which would be (0.0313725, 0.2, 0.04313725, 0). When I step through the shader, It also shows the same strange rgba values of (0.00244, 0.0332, 0.00336, 0.00):
    upload_2021-1-8_15-49-51.png

    (In the above code, xx is 1, yy is 0, and ts is _PosTex_TexelSize. So it should be reading the center of pixel location (0, 1). I can't figure out what these numbers are! I knew the numbers returned by tex2Dlod would be floats between 0 and 1, and they are, but I thought that I could turn them back into bytes simply by multiplying by 255. When I calculated what the multiplier would have to be to convert the number in the range 0..1 back to the original byte value, I realized that it doesn't seem to be linear because there isn't a single multiplier that could get all the numbers back to the original value.

    I made sure to turn off filters on the texture:
    upload_2021-1-8_16-32-28.png

    The texture was allocated like this:

    Code (CSharp):
    1. RenderTexture positionRenderTex = new RenderTexture(w, h, 0, RenderTextureFormat.ARGB32); // ARGB version
    I have a few theories:
    1. The first theory is that there's a strange internal "byte-to-float-between-0-and-1" conversion equation that I don't know about.
    2. The second is that perhaps when using tex2Dlod() on a RGBAHalf texture, a coordinate system is used that is different from the one used in RGB32 textures - thus I'm reading the wrong pixel and those strange values are actually for a different pixel?
    3. Maybe tex2Dlod is not meant for ARGB32 buffers and I should be using an alternative function?
    4. Could there be some sort of internal filtering that's changing the bytes that I wrote into the file?
    I dunno.... What am I missing here?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    By default any texture created not using a float format is set to be assumed to be an sRGB texture unless you specify otherwise. This means if you're using Linear Color Space for your project, when that texture is sampled the GPU applies an sRGB to linear color conversion.
    https://en.wikipedia.org/wiki/SRGB

    Make sure when creating your render texture you use
    RenderTextureReadWrite.Linear
    as the argument after the format.
     
  3. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    760
    That was exactly the problem!! Thank you! Thank you! Thank you!!!!

    I literally spent around 16 hours trying to fix that issue and you solved it in less than a minute. During my seach for answers I must have read at least 20 of your posts where you answered people's questions. I don't know who you are or where you're from... but the world is definitely better with you in it!
     
  4. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    760
    One quick side-note... At this point, I can accomplish my goal using either ARGBHalf or ARGB32. Part of the reason for using ARGB32 is for memory reduction, but it's not the only factor. I've been reading conflicting information about the two formats so I'm not really sure what to believe.

    I'm wondering which of the two formats would be faster on mobile devices. Originally, I assumed the floating point one would be slower, but I ran across a few statements saying that the floating point version could actually be faster on some GPUs. And of course there were many sources that stated the exact opposite.

    My second concern is how new does a device need to be before it can support ARGBHalf? The Unity docs just say "ARGBHalf is not supported on all devices" without going into detail. I know that for a while when it first arrived, some phones could read it but not write to it. At this point I'm only concerned with reading. Is it something specified in GL ES 3, or 3.1, or 3.2? Roughly... are we talking post 2005, 2010, or 2015?

    Thanks again for your help!
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    AFAIK GLES 3.0 requires RGBAHalf support. And I can’t imagine a single GLES 3.0 device being slower at rendering to or reading from a linear ARGB32 than ARGBHalf.

    But Android devices are crazy town. There are still some GLES 2.0 devices being sold out there, and there are devices that lie about what they support. And a surprising range of what “should” be faster being much slower on some GPUs. That said I know some high profile mobile devs have dropped GLES 2.0 at this point, so it’s probably safe to do so yourself.
     
    lclemens likes this.