Unity & PS Linear Workflow - Unity and PS Linear Workflow Practice - Simple configuration example (subsequent rendering difference map)


Purpose

Because the characters of the new Unity project follow the realistic PBR style
, the rendering effect based on Linear Workflow is definitely better than that based on Gamma Workflow.
However, the Linear Workflow is not very friendly to the art workflow. The following is an experiment and summarizes the advantages and disadvantages of some solutions
for everyone to choose.

Let's take a look at the difference in PBR selection under different Color Spaces

In Unity Linear Color Space, the rendering quality is close to SP (Substance Painter) and other PBR rendering effects of DCC software are selected

[Put some screenshots here, occupy the space first, and add them later]

As you can see, the Unity Gamma Space is really different

As for why there is a difference, you can refer to my previous article: Gamma Correction/Gamma Correction/Grayscale Correction/Brightness Correction (Corrected) - Linear Workflow Configuration in Part of DCC


question

The 3D rendering effect is much better under Linear Workflow

However , the production resources of UI or special effects art students are still based on Gamma Workflow (blog is written on: 2022/09/02, installed Photoshop is configured in the color space of Gamma Workflow by default, and future Photoshop versions may change, It may change when sRGB becomes obsolete)

Therefore, if the resources produced based on Gamma Workflow are used under Unity Linear Workflow, there will definitely be problems displayed.


Solution 1


PS color space configuration

I asked UI Specialty to give a special map made in gamma space
insert image description here

Then I put this Gamma space image under the PS after the adjusted color settings, the effect is as follows

(Without Gamma Correct, that is: pow(inputVal, 2.2), it feels too bright and gray, which is equivalent to this effect under Non-sRGB )

insert image description here


Unity Texture Settings

I exported the gamma.png image above as: linear.png, and then unchecked the sRGB of the texture ( ie: sRGB=false)

bg.png is also sRGB = false
insert image description here

Then put the two images on top of each other, as shown below, exactly the same as in Photoshop

insert image description here


GIF effect comparison

Please add image description


Advantages and disadvantages

  • A bit: 100% effect reduction
  • Disadvantages: The PS swatches are not balanced, the grayscale is lost, and if you use the PS color pipette to absorb the PS color, you will find that it is wrong, especially the color value of the content of other program windows unexpectedly absorbed by the PS program window

The disadvantages are detailed below:

But in this way, UI and special effects art are somewhat inconvenient in the production process of PS:

  • If it is the early stage of the project, it is better to use this workflow directly
  • If it is in the middle of the project, then all the previous hues and saturations need to be modified, which will make art students unacceptable
  • Moreover, some grayscales will also lose progress in the PS color palette (ie: some grayscales cannot be selected and used)

insert image description here

insert image description here


Solution 2


PS gamma Correct keep 2.2 & gamma 1.0 checked

insert image description here


Unity then textures sRGB = false and uses its own CustomShader to do Gamma Correct

insert image description here


CustomShader - UI/Default_Ext source code

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
// jave.lin : 2022/09/03 基于 unity 2020.3.37f1 的 builtshader 的 UI/Default Shader 修改而来

Shader "UI/Default_Ext"
{
    
    
    Properties
    {
    
    
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {
    
    }
        _Color ("Tint", Color) = (1,1,1,1)

        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _ColorMask ("Color Mask", Float) = 15

        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
        // jave.lin : 自己添加一个是否需要使用 gamma correct 的开关
        [Toggle(GAMMA_CORRECT_ON)] _GammaCorrectOn ("GammaCorrectOn", Float) = 0
    }

    SubShader
    {
    
    
        Tags
        {
    
    
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Stencil
        {
    
    
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend One OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass
        {
    
    
            Name "Default"
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
            // jave.lin : 使用一个全局变体 keyword,便于外部脚本 Shader.EnabledKeyword() 的方式来全局控制
            #pragma multi_compile _ GAMMA_CORRECT_ON

            struct appdata_t
            {
    
    
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
    
    
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord  : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
                float4  mask : TEXCOORD2;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _ClipRect;
            float4 _MainTex_ST;
            float _UIMaskSoftnessX;
            float _UIMaskSoftnessY;

            v2f vert(appdata_t v)
            {
    
    
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
                float4 vPosition = UnityObjectToClipPos(v.vertex);
                OUT.worldPosition = v.vertex;
                OUT.vertex = vPosition;

                float2 pixelSize = vPosition.w;
                pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));

                float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
                float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
                OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
                OUT.mask = float4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));

                OUT.color = v.color * _Color;
                return OUT;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
    
    
                half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);

                // jave.lin : 我们自己来添加 gamma correct
                #ifdef GAMMA_CORRECT_ON
                // jave.lin : 试过好几种数值,就这个是最接近的了

                // jave.lin : 写法1
                // // jave.lin : step1 : rgba 整体 pow(val, 2.2) 压暗
                // color.rgba = pow(color.rgba, 2.2);
                // // jave.lin : step2 : 单独对 a 通道 pow(val, 0.5) 曲线提升一些 alpha 值
                // color.a = pow(color.a, 1.0/2.0);

                // jave.lin : 写法2,在写法1基础上简化
                // color.rgb = pow(color.rgb, 2.2);
                // color.a = pow(color.a, 2.2 * 0.5);

                // jave.lin : 写法3,在写法2基础上,优化:充分利用 SIMD 4分量并行指令
                color.rgba = pow(color.rgba, half4(2.2, 2.2, 2.2, 2.2 * 0.5));

                #endif

                #ifdef UNITY_UI_CLIP_RECT
                half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
                color.a *= m.x * m.y;
                #endif

                #ifdef UNITY_UI_ALPHACLIP
                clip (color.a - 0.001);
                #endif
                
                color.rgb *= color.a;

                return color;
            }
        ENDCG
        }
    }
}


GIF effect comparison

Except the font alphablend is slightly different (this will be an experiment later)
Please add image description


Advantages and disadvantages

  • Advantages: In this way, UI and special effects art almost do not need to modify the workflow, as long as: alpha blend 1.0 is checked, and the function of the PS color pipette can maintain the original function effect, so it is the most friendly to the art workflow
  • Disadvantages: gamma correct (a pow operation) must be added to each UI or special effect shader. If there is a lot of overdraw, it will amplify the performance consumption of this point, but for modern graphics cards, it should be negligible.

Summarize

obvious

If you want to have better PBR 3D lighting effects in the linear workflow, but also have UI and special effects that are compatible with the previous version of the gamma workflow, then it is best to use: scheme 2 , the premise is: then a little bit performance loss is acceptable

If your project art can accept the grayscale of scheme 1, and the hue range is lost, you can choose scheme 1 , and the shader does not need to deal with gamma correct


Project

backup project (for backup)
Testing_UI_Default_CustomShaderGammaCorrect_in_Linear_workflow


References

Guess you like

Origin blog.csdn.net/linjf520/article/details/126672005
ps