Direct light implementation of Shader’s GI in Unity

Article directory

  • Preface
  • 1. In the previous article, after obtaining the GI related data, it is necessary to calculate the Lambert lighting model.
  • 2. After preparing the above steps, we need to prepare the missing data
    • 1. Prepare s.Normal in the picture above
    • 2. Prepare the s.Albedo in the picture above

Foreword

The direct light implementation of Shader’s GI in Unity, based on the data prepared in the previous article, continues to implement the direct light effect of GI

  • Judgment of Shader’s baking branch in Unity

1. In the previous article, after obtaining the GI related data, it is necessary to calculate the Lambert lighting model

This is the method to get GI data from the previous article
LightingLambert_GI1(o,giInput,gi);

After getting it, we can directly use Unity’s own function calculation to calculate the Lambert model. Of course, we can also implement the Lambert lighting model ourselves according to the previous article.

  • Implementation of Lambert lighting of Shader in Unity

This is how Unity implements Lambert lighting in Lighting.cginc

We transplant it to our own cginc to facilitate management and modification (remember to modify the function name to prevent function name conflicts)

2. After preparing the above steps, we need to prepare the missing data

1. Prepare s.Normal in the picture above

This has been defined many times in previous articles. The specific steps are as follows

1. In appdata, accept half3 normal: NORMAL;

half3 normal : NORMAL;

2. Define a half3 worldNormal in v2f: TEXCOORD; used to store vertex normal data

half3 worldNormal : TEXCOORD2;

3. In the vertex shader, convert the data passed in appdata into world coordinates and store it in worldNormal of v2f

o.worldNormal = UnityObjectToWorldNormal(v.normal);

4. In the fragment shader, assign worldNormal to Normal of SurfaceOutput variable

//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)
o.Normal = i.worldNormal;

Then, in UnityLambertLight1, we return the diff and see the result
In the fragment shader, return the calculation result

fixed4 c = LightingLambert1(o,gi);
return c;

This is the effect before baking:
Please add image description
This is the effect after baking: (We can see that there is already a basic lighting effect)
Please add image description

2. Prepare s.Albedo in the picture above

This Albedo is generally obtained by sampling the main texture of the model. We do not use it here, so it is generally assigned a value of 1 (it cannot be 0, otherwise the output result will be black)

The following is the complete modified code:

//Use custom cginc here to implement global GI
//Preparation of GI data
//Judgement of baking branch
//Direct light implementation of GI
//GI indirect light implementation
Shader "MyShader/P1_8_6"
{
    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
                half3 normal : NORMAL;
            };

            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
                half3 worldNormal : NORMAL;
            };
            
            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

                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                
                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)
                o.Albedo = 1;
                o.Normal = i.worldNormal;
                
                //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);
                //After we get the GI data, we calculate the Lambert lighting model and get the result.
                fixed4 c = LightingLambert1(o,gi);

                return c;
                //return fixed4(gi.indirect.diffuse,1);
                //return 1;
            }
            ENDCG
        }
    }
}

This is the modified effect:
Please add image description