Cause
Today, in the use of their own modified standard shader PBR effect, found that the project used substance export map application to unity is significantly brighter than the original software, the whole has a sense of hair ash, And the previous use of empty engineering, the effect and substance consistent. Initially thought it was shader, repeated check shader and texture are exactly the same, the sky box and ambient light direction light settings are the same, but the final effect is not the same.
Check out the substance export to Unity document HTTPS://SUPPORT.ALLEGORITHMIC.COM/DOCUMENTATION/DISPLAY/SPDOC/UNITY+5 and find that the first step is "in the" Player project Settings, set the color spaces to Linear, that is, you need to switch the color space of the project to linear space, see the project's color setting is gamma, try to switch to Linear space is working. Reasons to Explore
On the difference between linear and gamma space, Fengle's article sums up very well:
http://blog.csdn.net/candycat1992/article/details/46228771,
In Unity if you use gamma color space and do not do any manual processing, all the calculation process is in the gamma space, that is, the use of non-linear values as a linear value of the calculation, this process is undoubtedly wrong, in the simpler classical illumination model, Art can be manually adjusted to the unity of material material, to achieve the desired effect (through the wrong parameters and the wrong calculation process). And so without the correction of the input map color value, if used in PBR, this will be very biased, and the PBR material does not have enough parameters to manually adjust the results to the normal value (the calculation process is more complex), so in PBR must deal with gamma correction in order to ensure that the final results acceptable.
Does that make it easy to set the project color space to linear? On the PC platform this basically can solve the problem, but the mobile end will have a certain compatibility problem. According to the Unity Official document https://docs.unity3d.com/Manual/LinearRendering-GammaTextures.html for linear space Description:
Linear supported platforms Linear rendering is isn't supported on allplatforms. The build targets that support the feature are:
-Windows,mac OS X and Linux (Standalone)
-Xbox One
-PlayStation 4
-Android
-IOS
-WebGL
There is no fallback to gamma when linear rendering are notsupported by the device. In this situation, the Player quits. You can check the active color spaces from script by looking at Qualitysettings.activecolorspace. On Android, linear renderingrequires at least OpenGL ES 3.0 graphics API and Android 4.3. On IOS, linear rendering requires the Metal graphics API. On WebGL, linear rendering requires at least WebGL 2.0 API.
The Android device needs a system that supports OpenGL ES 3.0 and at least Android 4.3, and iOS needs the metal graphics API (at least iOS 8), and how much of this machine is.
According to Unity's own investigation https://blogs.unity3d.com/cn/2016/12/07/linear-rendering-support-on-android-and-ios/:
With Unity 5.5, linear rendering are now available on Android and IOS. On Android, linear rendering requires OpenGL ES 3 Graphics API which represents of the Android 61.1%. On iOS, linear rendering requires Metal graphics API which represents of the iOS 71.1%.
That is, 38.9% of Android devices and 28.9% of iOS devices are not able to use the linear color space, whether to be compatible with this part of the user, need each project for their own discretion. For our own projects, it is necessary to be compatible with this part of the user, so we need to be in the project color space set to gamma, in the shader of the input of the map color correction transformation. Operation Steps
There are two issues to be aware of when converting input map sampling values in shader:
You need to make sure that the input texture is gamma encoded, which is gamma coded. At present most of the art tools if the output does not go through special settings, the default is gamma encoding (which can be displayed directly on the monitor), but there are some special cases where the texture is directly in the linear space, for this part of the map does not need to convert, the result of the conversion is wrong.
Only textures that are color-only need to be converted, normal maps and channel control diagrams are not required. For textures that are numeric in content, the result of this part of the map in the art tool is linear, that is, no gamma conversion is required to be used directly.
Unity in the Unitycg.cginc header file provides Gammatolinearspace and lineartogammaspace for two space transformation, the algorithm is an approximate algorithm, the efficiency is relatively high, where the annotation points out the corresponding approximation algorithm introduction:
Inline Half3 gammatolinearspace (half3 SRGB)
{
//approximate version from http://chilliant.blogspot.com.au/ 2012/08/srgb-approximations-for-hlsl.html?m=1 return
sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.01252287 8h);
Precise version, useful for debugging.
Return Half3 (Gammatolinearspaceexact (SRGB.R), Gammatolinearspaceexact (SRGB.G), Gammatolinearspaceexact (sRGB.b)) ;
}
Inline Half3 lineartogammaspace (half3 linrgb)
{
Linrgb = max (Linrgb, Half3 (0.h, 0.h, 0.h));
An almost-perfect approximation from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html? M=1 return
max (1.055h * POW (LINRGB, 0.416666667h)-0.055h, 0.h);
Exact version, useful for debugging.
Return Half3 (Lineartogammaspaceexact (LINRGB.R), Lineartogammaspaceexact (LINRGB.G), Lineartogammaspaceexact ( linrgb.b));
}
It also provides a judgment function to determine whether the current project is under Gamma color space:
inline bool Isgammaspace ()
{
#if defined (unity_no_linear_colorspace) return
true;
#else
//UNITY_COLORSPACELUMINANCE.W = 1 Linear space, otherwise = 0 return
unity_colorspaceluminance . W = 0;
#endif
}
Depending on the return value of this function, you can choose to process or not handle the sample value for the map.
After changing the input map sampling value to the linear space in a slightly modified standard shader, and after gamma conversion in the final output, the result is basically consistent with the substance, the modified fragment is as follows, for input:
1, processing input reflectance map (albedo) of the sample value
Half3 Diffcolor = DiffuseAndSpecularFromMetallic1 (Albedo (I_tex), Metallic,/*out*/Speccolor,/*out*/ oneminusreflectivity);
Fragmentcommondata o = (fragmentcommondata) 0;
O.diffcolor = Gammatolinearspace (diffcolor);
O.speccolor = Gammatolinearspace (Speccolor);
2, processing environment map (introduction lighting) of the sample value
Unitygi gi = Unityglobalilluminationmad (d, Occlusion, S.normalworld, g);
Gi.indirect.diffuse = Gammatolinearspace (gi.indirect.diffuse);
Gi.indirect.specular = Gammatolinearspace (gi.indirect.specular);
return GI;
For output:
Half3 color = Brdf3_direct (Diffcolor, Speccolor, RlPow4, oneminusroughness);
Color *= light.color * NL;
Color + = Brdf3_indirect (Diffcolor, Speccolor, GI, grazingterm, fresnelterm);
color = LinearToGammaSpace1 (color);
return Half4 (color, 1);
This basically completes the standard shader in the gamma color space of the modified use.