Judgment of Shader’s baking branch in Unity

Article directory

  • Preface
  • 1. The lightmapUV required in the previous article will only be used during baking.
    • 1. After checking the help document, Unity uses LIGHTMAP_ON to determine whether baking is enabled.
    • 2. We define the second set of UVs in appdata and v2f

Foreword

Judgment of the baking branch of Shader in Unity, based on the previous article, continue to implement GI Shader

  • Preparation of GI related data for Shader in Unity

1. The lightmapUV required in the previous article will only be used during baking

That is, lightmapUV is only used under BackGI and RealtimeGI, so we need to use branches to distinguish

1. After viewing the help document, Unity uses LIGHTMAP_ON to determine whether baking is enabled

  1. DYNAMICLIGHTMAP_ON :RealtimeGI is on
  2. LIGHTMAP_ON: turned on when the object is marked as LightMap Static and the scene is baked

So, in Pass, we modify LightMode to ForwardBase
Define multi_compile_fwdbase variant

Tags{“LightMode”=“ForwardBase”}
CGPROGRAM
#pragma vertex vert
#pragma fragment fragment
#pragma multi_compile_fwdbase

2. We define the second set of UVs in appdata and v2f

1. In appdata, the semantics corresponding to the second set of UVs is TEXCOORD1, which cannot be changed randomly.

struct appdata
{
float4 vertex : POSITION;
//Define the second set of UVs. The fixed semantics corresponding to appdata is TEXCOORD1
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
float4 lightmapUV : TEXCOORD1;
#endif
};

2. In v2f, a second set of UVs is also defined, but there are no semantic restrictions here

struct v2f
{
float4 vertex : SV_POSITION;
float4 worldPos : TEXCOORD0;
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
float4 lightmapUV : TEXCOORD1;
#endif
};

3. Sample it in the vertex shader

float4 lightmapUV; // .xy = static lightmap UV, .zw = dynamic lightmap UV
The XY of lightmapUV represents: BackGI
ZW of lightmapUV stands for: RealTimeGI

//Texture sampling for the second set of UVs. This unity_LightmapST is similar to the Tilling and Offset we defined the texture before.
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
o.lightmapUV.xy = v.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
#endif

4. In the fragment shader, assign a value to it

#if defined(DYNAMICLIGHTMAP_ON) || defined(LIGHTMAP_ON)
giInput.lightmapUV = i.lightmapUV;
#endif

Here is the code after all the data is ready:

//Use custom cginc here to implement global GI
//Preparation of GI data
//Judgement of baking branch
Shader "MyShader/P1_8_4"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment fragment
            #pragma multi_compile DYNAMICLIGHTMAP_ON
            #pragma multi_compile LIGHTMAP_ON
            

            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #include "Lighting.cginc"
            #include "CGIncludes/MyGlobalIllumination.cginc"
            
            struct appdata
            {
                float4 vertex : POSITION;
                //Define the second set of UVs. The fixed semantics corresponding to appdata is TEXCOORD1
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                float4 lightmapUV : TEXCOORD1;
                #endif
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 worldPos : TEXCOORD0;
                //Define the second set of UVs
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                float4 lightmapUV : TEXCOORD1;
                #endif
            };
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);

                //Texture sampling for the second set of UVs
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                    o.lightmapUV.xy = v.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
                #endif
                
                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //1. Prepare SurfaceOutput data
                SurfaceOutput o;
                //Currently initialized to 0, use Unity's own method to initialize the contents of the structure to 0
                UNITY_INITIALIZE_OUTPUT(SurfaceOutput,o)

                //2. Prepare data for UnityGIInput
                UnityGIInput giInput;
                //initialization
                UNITY_INITIALIZE_OUTPUT(UnityGIInput,giInput);
                //Modify the data used
                giInput.light.color = _LightColor0;
                giInput.light.dir = _WorldSpaceLightPos0;
                giInput.worldPos = i.worldPos;
                giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
                giInput.atten = 1;
                giInput.ambient = 0;
                
                #if defined(DYNAMICLIGHTMAP_ON) || defined(LIGHTMAP_ON)
                giInput.lightmapUV = i.lightmapUV;
                #endif
                
                //3. Prepare UnityGI data
                UnityGIgi;
                //Direct lighting data (main parallel light)
                gi.light.color = _LightColor0;
                gi.light.dir = _WorldSpaceLightPos0;
                //Indirect lighting data (currently give 0)
                gi.indirect.diffuse = 0;
                gi.indirect.specular = 0;
                
                LightingLambert_GI1(o,giInput,gi);
                return 1;
            }
            ENDCG
        }
    }
}