Search Unity

Bug with Bypass sRGB Sampling?

Discussion in 'General Graphics' started by topsekret, Nov 27, 2014.

  1. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    We recently switched our project from Gamma space to Linear space to take advantage of its benefits for lighting. However, our UI looks significantly worse in Linear space.

    We would like to fix this issue without re-authoring every UI texture in our game. The last section of this article from Unity seems to indicate that if you want to make your UI look like it did in Gamma space, you should be able to just set the texture to "Bypass sRGB Sampling". However, this flag did not fix my problem; in fact, it made the UI look worse.

    I have created and attached a small project to illustrate the problem. (The project was created in Unity5 beta 13, so it is not compatible with Unity4, sorry! However, I have observed this problem in Unity4 as well, so it seems independent of Unity version.)

    There are six important elements on screen in the project:
    1. A UI icon from our game without "Bypass sRGB Sampling" set.
    2. A UI icon from our game with "Bypass sRGB Sampling" set.
    3. An alpha gradient (rgb is white, a goes from 0-1) without "Bypass sRGB Sampling" set.
    4. An alpha gradient (rgb is white, a goes from 0-1) with "Bypass sRGB Sampling" set.
    5. A greyscale gradient (rgb goes from 0-1, no a) without "Bypass sRGB Sampling" set.
    6. A greyscale gradient (rgb goes from 0-1, no a) with "Bypass sRGB Sampling" set.

    By default, the project is set to Gamma space. Both versions of the UI icon look the same and look correct. (See attached image "GammaSpace.png".)
    GammaSpace.png

    If you switch the project to Linear space, you will see that the icon looks much worse. In particular, the alpha values are much higher, making the glow much more opaque than intended. If you look at the icon that is set to "Bypass sRGB Sampling", you will see that it has the same problem with alpha, but it also has the problem of making the pink color much brighter than it should be. (See attached image "LinearSpace.png".)
    LinearSpace.png

    We can diagnose what is happening to the icon by looking at how the change from Gamma to Linear affects the alpha and greyscale gradients with and without "Bypass sRGB Sampling".

    If you look at the alpha gradient when switching from Gamma to Linear, you will notice they both have some kind of curve applied to them causing the alpha values to increase. I would expect that "Bypass sRGB Sampling" would make the alpha look the same as it did in Gamma. Is this a bug?

    If you look at the greyscale gradient when switching from Gamma to Linear, you will notice that the gradient without the "Bypass sRGB Sampling" flag set looks the same. But the texture with the flag set has its greyscale values increased. This is the opposite of what I would expect. Is this a bug?

    Can anyone confirm that this behavior is a bug, or justify why it behaves this way?

    (As an aside, I have observed a bug that is less concerning, since it is easy to circumvent. When you switch the project from Gamma to Linear for the first time since launching the editor, rgb values seem to not be influenced by the "Bypass sRGB Sampling" flag at all. However if you switch back to Gamma, then back to Linear, it should appear how I described it previously. See the attached image "LinearSpace_Bug.png" for an example of what this looks like.)
    LinearSpace_Bug.png
     

    Attached Files:

  2. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Can you place log a bug for this so we can investigate in more detail (please paste the bug# here)
     
  3. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Is this on Unity5 or 4.6?
     
  4. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    The attached packed is not working with Unit 4.6
     
  5. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    Sorry for the sluggish reply; I'm in the U.S. so I was out for Thanksgiving.

    I just submitted a bug report through Unity (case number 652537).

    As I said before, the project was created in Unity 5 beta, so unfortunately, it will not work in Unity 4. However, I have done small tests and confirmed that it is indeed a problem in Unity 4 as well. If you would like, I can recreate the project in Unity 4 to demonstrate that it is an issue there as well. (It will just take me an hour or so to set everything up again.)
     
  6. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    I sent an email response, but in case anyone is curious:

    Hi,

    So what you are seeing is actually intended behavior, even though it really may not seem that way. Let me explain.

    *The first issue is the bypassing of sRGB sampling. This should only be used for legacy IMGUI. IMGUI renders AFTER scene rendering when linear rendering has been disabled, so we need to mark the texture to not be linearized on sample. Your UI is rendered in the world so this is not applicable here. This may be changing for 5.0, the graphics team is talking about it currently.

    *When switching to linear mode it (greatly) changes how blending works, this is because when sampling only the rgb channels are linearised as it is assumed the alpha is a linear scale representation already. That's just how it's designed (http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html). This is all well and good for normal scene rendering, but it does cause some issues when it comes to UI. Essentially in your example whats happening is that alpha is getting pushed out because it is assumed to be in linear when it's been authored in gamma space. If you take a look at this link you can see that when alpha blending gamma vs linear the results are quite different:
    https://docs.google.com/spreadsheets/d/1-6J_pAatXuAx7x5WwtN6RxoKGToBVZTn3zVyzl85Fm4/edit?usp=sharing
    Feel free to input your own values and have a play.

    The issue is basically that the content has been authored for gamma blending but not linear. There are two ways this can be fixed:
    1) Reauthor the content for linear blending (this is supported in photoshop).
    2) Add a workaround in the shader if in linear space to 'pretend' the alpha from the source texture is in the correct format. An example of how to do that is here (http://hastebin.com/webexacepa.avrasm).

    -Tim C
     
  7. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Note: the shader workaround requires Unity 5.
     
  8. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    Thank you for the detailed reply, Tim!

    Unfortunately, fixing this with option 1 (reauthoring our UI textures for Linear), is not a good solution for our project. We still need to support gamma space for the mobile version of our game. So this would require us to develop a system for swapping textures at both build time (for maximum space efficiency) and run time (for easy testing in the editor).

    For us, option 2 (using a custom shader to correct the issue) is the most feasible solution. However, the shader at the link that you provided does not actually fix the issue. I have modified the project I attached in my first post to use the custom shader to demonstrate the problem.

    In the below image, the project was set to Gamma color space. As expected, the icon with the normal Unlit/Transparent shader and the icon with the correction shader you provided look the same
    CorrectionShader_Gamma.png

    In the below image, the project was set to Linear color space. As expected, the icon with the normal Unlit/Transparent shader looks different in Linear space. However, even the icon with the correction shader looks different-its semitransparent glow has been virtually eliminated.
    CorrectionShader_Linear.png

    Basically, all the correction shader is doing is raising the alpha channel to the 2.2 power if we are in Linear color space. Based on the results of testing this, I think it is safe to say that this is not the correct way of fixing the issue.

    Can you think of any other calculations we would need to do in the shader to get this to work?
     

    Attached Files:

  9. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Well the blending IS different between the two modes and the only way to get them to look exactly the same is to reauthor the content. The shader trick is a workaround which gets you some of the way there, but it's not perfect.
     
  10. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    It seems strange to me that there is no way to fix this perfectly with a shader. Reauthoring a texture amounts to you opening up Photoshop and applying some function to each texel. If this were in fact able to fix the issue, then it would be possible to put that function in the shader instead.

    Perhaps the reason this can't be fixed elegantly in the shader is that the function to correct the textures cannot be represented elegantly with a simple curve (ex: polynomial, exponential, etc...)? Wouldn't it at least be possible to get a better approximation of the correction function than the exponential with the power of 2.2 by using some sort of piecewise function?
     
  11. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Unfortunately it can't be emulated in the shader due to blend units being fixed function. We don't have the control to modify incoming destination values pre blending, it's all configured via the sRGB texture format / float texture format :(
     
  12. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
  13. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    I see. So if the main problem is that we can't apply a function on the destination values read for blending, then this probably can't be "perfectly" fixed (meaning that when rendering a sprite to the screen, each pixel will look exactly the same as it did in gamma space) with a shader or reauthoring textures.

    I guess the best we can do is try to fake it either with a curve in the shader or reauthoring textures, but it will never be exactly the same in all cases.

    Hopefully one day we'll have programmable blending!
     
  14. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    A few weeks ago I discovered a workaround for this, so I thought I would post it here in case others run into this problem.

    As we know, the blending does not look the same because previously we were bending in gamma space, but now we are blending in linear space.

    To get around this for the UI, what we can do is use a post effect to encode gamma into the back buffer right before the UI camera renders. Then, assuming the UI textures are set to "Bypass sRGB Sampling", the colors returned by the pixel shaders for the UI will be in gamma space and will blend properly with the gamma space back buffer. Finally, once the UI camera has finished rendering, we simply apply another post effect to decode the gamma from the back buffer.
     
  15. snlehton

    snlehton

    Joined:
    Jun 11, 2010
    Posts:
    99
    I don't know if this has changed lately, but I'm seeing big problems with the new UI and linear mode.

    Using Unity 5.0.1f1 in linear color space.

    I've isolated one problem to be the alpha that you set as the sprite color.


    So for some reason the white square ends up too bright on linear mode, while in gamma it looks as expected.

    This has nothing to do with the texture sRGB bypass, as the texture is unaffected by the gamma/linear mode.

    What could be reason for this? It also makes tweaking colors for the sprites in the linear space a bit pain, as the expected 50% is way too strong, and the actual noticiable alpha fading happens from 50% <-> 0%.

    For example I made a full screen sprite that is used to fade the screen to black. I animate the color alpha linearly, but the result looks really weird. The longer the fade is, the more wrong it looks as first nothing seems to happen, and then suddenly it fades to black.
     
    Last edited: Jun 4, 2015
  16. snlehton

    snlehton

    Joined:
    Jun 11, 2010
    Posts:
    99
    Here's another example. White hexagon sprite where the color has been set to red.



    Bottom one has color (1,0,0,1). Top-left has color (1,0,0,0.5) i.e. 50% opacity. It looks almost as bright as the 100% opacity one. Top-right has color (0.5, 0, 0, 1) i.e 100% opacity but intensity has been reduced to 50%.

    In linear mode both upper icons look exactly the same.
     
  17. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    Your images look broken. Did you embed them into your post correctly?
     
  18. v.nikolaev

    v.nikolaev

    Joined:
    Sep 11, 2015
    Posts:
    7
    Hi, maybe you can tell how to change color space for textures in photoshop?

    Also, i have modified unity's UI-Default.shader, and now it seems to display UI sprites with alpha gradient almost correct. The shader, that you proposed does not hide the sprite by the Mask ui-component.
     

    Attached Files:

  19. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    So, what the resolution? Is there any way to fix this problem without reauthoring content?
     
  20. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Could you please share this workaround or explained a bit more? I tried to write PostEffect that simply do pow(color, 2.2) on the src render texture, but it applies this on the background scene too. And how do you apply this solution in edit mode?
     
  21. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    I implemented my solution with 4 cameras rendered in the following order:

    1. First camera renders the game world. After this camera finishes rendering, frame buffer is in linear space.

    2. Second camera culls everything and only clears the depth buffer. It has a post effect to convert the frame buffer from linear to gamma space.

    3. Third camera renders the UI and only clears the depth buffer. UI content was authored for gamma space and because now the frame buffer is also gamma space, it alpha blends correctly.

    4. Forth camera culls everything and only clears the depth buffer. It has a post effect to convert the frame buffer from gamma back to linear space cause this is what space Unity expects the frame buffer to be in when the project is set to linear space.

    You could probably also do this with just two cameras and have the post effect script on cameras 2 and 4 happen on cameras 1 and 3 instead as long as they are the last post effects on their respective cameras.
     
    agebreak likes this.
  22. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Thank you, this solution works.

    Is there any way to apply this posteffects to the editor camera? Because now it is a bit hard to work with UI in the editor.
     
  23. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    May I ask how to reauthor a content? Didn't find the solution by searching in google..
     
  24. WQ-Charles

    WQ-Charles

    Joined:
    Feb 27, 2017
    Posts:
    5
    I cont find how to change color space for linear blending in photoshop?:(
    I tried the second way, but there is no 100% reduction.
     
  25. Becoming

    Becoming

    Joined:
    May 19, 2013
    Posts:
    781
    To linearize an sRGB texture in photoshop you need to use levels:
    linear.jpg

    However, i would not recommend this as it can lead to visible banding.
    Another (better) way is to use pow in the shader:

    Code (CSharp):
    1. //Linearize
    2. value = pow(value, 2.2);
    3. //De-Linearize
    4. value = pow(value, 0.4545);
    If you need to have a texture to have sRGB turned off in the import settings(eg. for custom normal map unpacking) and still need to have some channels to be in sRGB(or vice versa), using the above pow trick will help to get the same look as changing the import settings.
     
  26. WQ-Charles

    WQ-Charles

    Joined:
    Feb 27, 2017
    Posts:
    5
    Thank you! :)
    I decided to use pow in the shader.
     
  27. rainini

    rainini

    Joined:
    Nov 26, 2015
    Posts:
    3
    thanks for the hint, i try you solution ,it works when we use NGUI, i upload a package which i use in my project, u guys can use it and modify the depth of your maincamera and ui camera to follow the order that this solution needs.
    ps:all ui textures authored in srgb color space, and bypass the srgb correction in unity.
     

    Attached Files:

  28. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    I just wanted to confirm that we're using this in a project where GUI assets have been created in Illustrator, where we can't find a way to work in linear space, and it's working for us. I have not yet formally tested the performance impact.

    I did make one change, which was to replace the conversion lines with calls to Unity's provided LinearToGamma(...) and GammaToLinear(...) functions.

    Clearly it's best to have your stuff authored in the right colour space in the first place, but if that's not an option for whatever reason then this seems to get the job done.
     
  29. WookieWookie

    WookieWookie

    Joined:
    Mar 10, 2014
    Posts:
    35
    @Tim-C and others mentioning texture hacks...

    Many, many elements in a modern UI are made with no texture assigned, only a color selected on the Image. The project I'm on is an enormous social mobile project for a top grossing publisher, and the UI images folder is less than 3MB. The UI is mostly Images set to white with procedural gradients applied. Texture import or Photoshop hacks do not fully address the issue. Neither do multiple cameras and render textures, in a mobile (performance-sensitive) context.

    Not being clear and up front about this blending issue in the UI in your documentation has led us all here and caused a lot of frustration and arguments. This is a project setting that has major implications. And given that all mobile games contain a ton of UI and that that UI will need to do a lot of blending, Unity should be recommending Gamma blending for mobile projects and Linear blending for "other" projects with a lot less UI and loftier lighting goals.
     
  30. firstuser

    firstuser

    Joined:
    May 5, 2016
    Posts:
    147
    I get what you're saying and agree about the confusion, but I don't think this would be good advice, majority of mobile projects (at least anything touching 3D) will typically benefit from linear over gamma in my opinion.