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. Join us on Dec 8, 2022, between 7 am & 7 pm EST, in the DOTS Dev Blitz Day 2022 - Q&A forum, Discord, and Unity3D Subreddit to learn more about DOTS directly from the Unity Developers.
    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

Invert in Linear Color Space

Discussion in 'Shaders' started by flogelz, Jul 11, 2021.

  1. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    130
    Hey everyone,
    probably a basic question about color spaces, but i can't quite wrap my head around it. I've implement a simple Invert Postfx (v2 Stack) that just blits the source image into the destination and the inverts it (all values are between 0-1).

    Code (CSharp):
    1. return 1 - screenColor;
    Nothing fancy. In this example, the Background is black, the left cube white and the right cube 50% grey.
    In Gamma Mode, this works like expected, in linear it doesnt- I may be wrong but isn't the whole point of linear color space, that textures (so also the screen texture) are interpreted linearly? Because here it looks like the complete opposite is happening- Maybe someone as an idea about this.

    GammaLinear.png
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,834
    In what color space?

    True “50% grey” in sRGB is ~0.214 in linear.

    sRGB more closely matches what the human perception of color is, so “50% grey” looks like it’s half way between black and white, but in reality is no where close. Something that’s “half as bright” as something else is really emitting 20% of the photon energy.

    Linear space rendering gets converted back to sRGB before being displayed on screen. If you want to invert a linear space rendering while keeping 50% grey looking like 50% grey, you’ll probably want to convert to sRGB, invert, then convert back to linear for output.
     
    flogelz likes this.
  3. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    130
    The material of the cube has a 128/128/128 color value on an unlit shader (and the scene above was in both linear and gamma, but the color didn't change at all when switching colorspaces). Does that mean that theres some sort of code in there, that converts the colors so that they don't change?

    This works nicely. (I can use the #ifdef UNITY_COLORSPACE_GAMMA too to make it work with gamma too). So thats working now, thank you!

    Does that mean tho, i have to look out for every postfx effect and convert everything correctly at the end?? (ex: I just blit a texture to the screen as another test case (in linear color space) with a shader that just outputs a float over the whole screen. And i had to convert the output from gamma to linear in shader to make it work linearly in the editor like youd expect it to work (50% on the float slider = 128 grey).
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,834
    Yep. Material properties defined as a
    Color
    in the shader are converted from sRGB to linear before being sent to the GPU if using linear color space so that they continue to look how you expect the color to look. This is just like textures which when set to be “sRGB (Color Texture)” will be converted from sRGB to linear when sampled by the GPU hardware to keep the color values looking how you expect.

    Shader color values not explicitly defined a
    Color
    material property, like if it’s defined as a
    Vector
    , or not defined at all, won’t get converted. So if you set color values from script you have to be mindful of this and do the conversion in your code. It’s important to note
    Material.SetColor()
    doesn’t itself do any of the color conversion, and if you set
    Color
    property values with
    Material.SetVector()
    they’ll still get color corrected. Conversely using
    Material.SetColor()
    on
    Vector
    properties will not mean values get color corrected. Instead you need to check the value of
    PlayerSettings.colorSpace
    and choose between using
    myColorValue
    directly and
    myColorValue.linear
    .

    Depends on the post effect, but yes it’s something you have to be mindful of. Linear space color also changes how all alpha blending looks.
     
    flogelz likes this.
  5. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    130
    Ok interesting, thanks for clearing this up. Makes a lot more sense now. Everywhere is written "use linear instead of gamma" but these small important bits never got mentioned- (or atleast i didn't see them). Thanks again!
     
  6. sharkwithlasers

    sharkwithlasers

    Joined:
    Dec 8, 2012
    Posts:
    22
    I'm curious if there's a way to do this (convert to sRGB->invert->linear) with the method shown by you in this post: here? https://forum.unity.com/threads/invert-the-colors-of-the-camera.486834/

    I'm using linear space, but I don't need a fullscreen effect for my color inversion.

    I guess I'm unsure what space the DstColor is in when doing `Blend OneMinusDstColor Zero`, and if its in linear space, is there a way to convert it back to sRGB, invert and then back to linear?
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,834
    Nope.

    If you’re rendering using linear color space, it’s in linear color space. If you’re rendering in gamma color space, it’s in gamma color space. That’s it. If you want to convert back to gamma space before inverting, you have to do that with a post process of some kind.
     
    sharkwithlasers likes this.