It is a known problem that the default Tone Mapping/Gamma Correction/Color Grading in UE4 alters the brightness and colors of textures, and not in a good way. Like many other people, I ran into this problem and lost a few days trying to get the engine to show the original colors of my textures.
Here are some old posts that already contain a lot of information and helped me to figure this out:
- Gamma/Tone Washing Out Image - How to Fix? - UE4 AnswerHub
- My pretty textures are being washed out by lighting - Rendering - Unreal Engine Forums
- How can I remove tonemapping in Play mode? - UE4 AnswerHub
- How do I disable Gamma Correction? - UE4 AnswerHub
With this post I would like to
- Illustrate the problem with a (hopefully) objective reference image
- Share the solution that I found
- Make Epic aware of this problem and ask what can be done
Here is my test setup:
No surprises in the material:
I’ve tried to disable all post process settings:
As texture I’m using the test image http://www.indiev.org/wp-content/uploads/2011/07/color-test-file.jpg
Modified Texture Settings:
- Never Stream
- No MipMaps
This is the original test image:
Here is how the image is rendered in UE4 by default using Auto Exposure (this is a screenshot of play in editor):
Pretty bad, I would say.
- The skin tone is altered a lot
- Brightness 242 and 255 are nearly identical
- White at 255 is now actually gray
To solve this, CWeatherman has proposed to change line 303 of \Unreal Engine\4.5\Engine\Shaders\PostProcessTonemap.usf like this:
//OutColor = float4(TonemappedColor, LuminanceForPostProcessAA); OutColor = float4(LinearColor.rgb, LuminanceForPostProcessAA);
This produces the correct output test image (if sRGB is disabled in the Texture) as shown by CWeatherman, however it makes the Starter Map look like this:
This was not acceptable for me. I tried to find a way how to get the correct output image without altering the look of existing scenes. Here is the solution I found:
- Don’t change anyting in PostProcessTonemap.usf
- In line 62 of TonemapCommon.usf at the end of the FilmPostProcess function, make this change (then save the usf file and restart the engine):
//return CurveColor; return MatrixColor;
This just disables the section titled “Apply color curve (includes tonemapping)” of the FilmPostProcess function. The section “Color and exposure control” is still active.
- Uncheck the sRGB checkbox in the texture details panel.
- In your material, add this after the Texture Sample Node:
Why, you may ask? Because it is the inverse of the function LinearToSrgbBranchingChannel that can be found in line 48 of PostProcessTonemap.usf:
return pow(lin, (1.0/2.4)) * 1.055 - 0.055;
- Set Min Brightness and Max Brightness to 1, and play around with the intensity of your directional light until the images match.
With these five steps, the engine renders the following image:
I suggest to open the images in separate tabs to compare them.
The Starter Map looks good too:
So it is definitely possible to get UE4 to render textures correctly. I think this should be the default behavior, the current behavior could be optional and actively enabled by the user.
Imagine you need to import a skin texture, by default it would look like in the image above.
I think Epic should add an option during texture import for people who do not want the look of the texture to change. Alternatively, please provide documentation/tutorials how to achieve accurate colors without changing stuff in the shader source code.
How is the average user supposed to avoid the subtle mistakes demonstrated here with the current behavior of the engine and the state of the documentation?
I hope this helps anyone who struggles with the same problem. Please let me know if you think my solution can be improved. Maybe it is possible to also undo the stuff from “Apply color curve (includes tonemapping)” in the material? This way, we would not need to edit the shader source code.
Edited: Wiring in material screenshot was wrong