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

Question Write nagative value to Texture2D

Discussion in 'General Graphics' started by SandiagoChan, Sep 23, 2021.

  1. SandiagoChan

    SandiagoChan

    Joined:
    Aug 8, 2017
    Posts:
    19
    Is it possible to save nagative value in texture file? I write nagative value by set pixels to texture2D(RGBA 64) and save as PNG,but the value read from the file by get pixel or in shader is zero.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Yes.*

    But no.

    PNG files can't store negative values. They can't store any values outside of a 0.0 to 1.0 range. So as soon as you save it as a PNG it's been clamped to that range. Additionally, while PNG does support 16 bits of precision per channel similar to an RGBA64, Unity's PNG exporter only supports saving 8 bits per channel. And depending on which version of Unity you're using, it may only support importing 8 bit per channel PNGs as well.

    If you want to save an image to disk with support for negative values, you'll want to save it as an EXR file. That's a format that supports 16 bit floating point, 32 bit floating point, and 32 bit unsigned integer. RGBA64 is a signed integer format, which the OpenEXR format can't do, so I don't know if it'll be saved as a 32 bit floating point, in which case you'll lose some of the range, or a 32 bit unsigned integer, in which case you'll lose the negative values again. Depending on what you're doing, you may be better off using the RGBAHalf format which can be perfectly represented by the EXR file.

    * But, there's one gotcha. If your project is using gamma color space, none of this will work. Not because the file won't be saved with a negative value, but because Unity will apply a color correction to EXR files that cannot be disabled which clamps the image to positive values in import. The only work around at that point is to not save the file as an EXR, or PNG, or any other image format Unity can export. Instead you would save the Texture2D directly as an asset.
     
  3. SandiagoChan

    SandiagoChan

    Joined:
    Aug 8, 2017
    Posts:
    19
    As your suggestion, I write negative values to texture2D(RGBA Half), and save the data(by Texture2D.EncodeEXR()) as xxx.exr file(no mip,point filter,RGBA Half). But the value read from texture file in the shader still zero.
     
    Last edited: Sep 27, 2021
  4. BOXOPHOBIC

    BOXOPHOBIC

    Joined:
    Jul 17, 2015
    Posts:
    506
    Hi. You can always remap the negative values to a positive range, something like:
    -100 to 100 > 0 to 200
    value = value + 100;

    Then in the shader remap it back:
    value = value - 100;

    I hope this helps :)
     
  5. SandiagoChan

    SandiagoChan

    Joined:
    Aug 8, 2017
    Posts:
    19
    It can work, but I need store matrices which not suitable with this way
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Yeah, for matrices, you absolutely want to be using ARGBHalf or ARGBFloat textures and an exr to store it (if not storing the Texture2D directly). There are use cases where packing data into a lower bit depth texture that you then rescale to the ranges you want/need, like for some vertex animation or morph textures, or 99% of normal maps, but generally you'll need more precision than that for matrices.