- Home /
Image effect "Color Correction Curves" doesn't work correctly with Linear Space rendering ; how to fix that ?
Hello,
title says it all : Image effect "Color Correction Curves" doesn't work correctly with Linear Space rendering ; how to fix that ?
More explanations : I'm creating a brightness slider using the "Color Correction Curves" Image effect ( http://docs.unity3d.com/Documentation/Components/script-ColorCorrectionCurves.html ).
===1st Issue=== SOLVED!
The expected result, which I'm getting with Gamma Space rendering is : http://s12.postimage.org/fiuwyv2r0/Color_Correction_Curve_Gamma_Space_Rendering.jpg
The actual result, with Linear Space rendering is :
http://s12.postimage.org/71venxy25/Color_Correction_Curve_Linear_Rendering.jpg
For comparison, without brightness change :
http://s10.postimage.org/bip58xea1/Color_Correction_Curve_Off.jpg
As you can see by looking at the created curve, it's like 95% of the colors are mapped within [0; 0.01], while the 5 other % are within [0.01; 1] (ie: all values within [0.01; 1] should be remapped to 1 after the correction, and it's obviously not the case).
I checked the remapping texture creation (the colors are remapped using that texture), and the result is same either "linear" is true or not. I checked the texture filling, and the correct values are put in it.
ANSWER: I found what's going on : this is actually a normal result. The screen in Linear space is more dark, thus there are a lot of pixels with 1 or more of their RGB channels to have a value of 0, 1, 2 or 3, thus even with full brightness on [4;255] ( = [0.0125; 1] which is my exact range giving an output value of 1 in my curve), there are a lot of pixels who don't end fully white, but instead they end pure yellow, or even in mid-tones.
2nd Issue: In Progress!
The Image Effect "eats" the dark colors, even with 1:1 curve (ie: f(x) -> x).
Look this, this is without the effect enabled :
http://s11.postimage.org/caqh99dib/Color_Correction_Curve_Dark_Details_Ok_If_Off.jpg
Now, with the effect enabled, with a flat curve (y = x) :
http://s11.postimage.org/ruxuzsnmp/Color_Correction_Curve_Dark_Details_Gone_If_On.jpg
The colors which RGB values are under about 10/255 in the 1st screen ends all being at 0 in the 2nd screen.
According to this http://docs.unity3d.com/Documentation/Manual/LinearLighting.html , as I'm using HDR mode, the render buffer should be in float, thus it should support reading & re-writing without losing these dark details, but it doesn't.
How to make it work ? Should I modify the texture type ? The way the shader works ?
Thanks in advance for any help about this matter..!
About the 2nd issue... In ColorCorrectionCurvesSimple.shader, I tried to use Float ins$$anonymous$$d of Fixed, then changed to Half, and with all cases it gives the same result : low values are getting zero'ed... I'm kinda stuck now, no more idea... :-/
I did some more tries in ColorCorrectionCurvesSimple.shader ; I put a direct value to the R channel : float3 red = float3(0.5,0,0); then I did a screenshot & checked the actual output R value.
1 gave 255 (normal)
-> 188 (should be 187, but still ok)
-> 89 (should be 90, but still ok)
0.05 -> 63 : should be 66, but not too bad
1/255 -> 13 : should be 21, this is bad
0.5/255 -> 7 : should be 15, ... ditto
0.3/255 -> 4 : should be 12, ... ditto
0.25 / 255 -> 0 : should be 11, this is very bad..!
This makes me wonder how the floating point rendering buffer is dealt with. Is it handled by the GPU that does the gamma correction by itself ? Or is there another conversion pass done by Unity engine ?
Just in case, I tried to add 0.25/255 to each channel, but this only lighten the output ; this probably means that the sampling of the remapping texture is also not accurate enough ; ie: a final output of 1/255, means the value in the linear buffer is around 0.000005 ( = 5e-6), so the coordinate x used for the texture look-up is 0.000005 which might be rounded to exactly 0 (and thus return a value of 0 ins$$anonymous$$d of 0.000005 by Tex2d() ).
And "funnily", if I set the curve to 0.3/255 , I'm getting a final result of 18 (ins$$anonymous$$d of 4 if 0.3/255 is forced within the shader).
I also checked the output histogram of each RGB channel value, and without the image effect applied, it's a nice curve, but with the image effect applied, there are a bunch of holes in the curve, showing the remapping is actually skipping some values... :-S
All in all, that's quite painful to figure out what's going on & how to fix it... :-/
Ok, I found a solution to my issue : to not use Color Correction Curve..! ;-) => ie: to not use a texture to remap the colors.
Ins$$anonymous$$d, I use the CG Pow() function, like this :
half4 frag(v2f i) : COLOR { half4 color = tex2D(_$$anonymous$$ainTex, i.uv); return pow(color, _Gamma); }
It's as fast on my GPU as the Color Correction, and result is perfect for gamma correction. I cannot do the enhanced brightness correction I was doing with the Curves, but I went into it only coz the gamma correction was bad (due to the aforementioned failure at low intensity). So now, it's alright ! ;)
Answer by manutoo · Sep 16, 2012 at 07:09 AM
Ok, I post a self-answer :
About 1st issue, as explained in the question : in the linear space render buffer, dark values get much darker, as the linear space intensity (LSI) is equal to power(Gamma Space Intensity, 2.2). It means, 1/255 in the final output is pow(1/255, 2.2) = 0.0013/255 in the Linear buffer, and 10/255 is 0.2/255, and 21/255 is 1.05/255 . This means the whole [0-20] range equals 0 if floored to a classic 8 bits buffer.
Thus the surprising result I got with the whole range [0.0125; 1] being remapped to 1, and 0 being still mapped to 0.
About 2nd issue, as explained in the comments : the issue comes from the texture sampling that is not accurate enough. The solution is to dump the texture sampling all together, and use pow() function ( = gamma correction) directly within the fragment shader to get a correct result, like this :
half4 frag(v2f i) : COLOR
{
half4 color = tex2D(_MainTex, i.uv);
return pow(color, _Gamma);
}
It means I can't use too special curves, but in my case, it's alright.
As this issue can raise with all Image Effects using a texture to remap the RGB channel values while using a Linear Space render buffer, I hope these explanations will save a few headaches to fellow coders... :-)
And if you use HDR and want some gamma/brightness correction, have a look at Tonemapping effect, it can do the trick (it's much more complex than a gamma correction though).
Your answer
![](https://koobas.hobune.stream/wayback/20220613081030im_/https://answers.unity.com/themes/thub/images/avi.jpg)