inline UnityGI UnityGI_Base(UnityGIInput data, half occlusion, half3 normalWorld)
{
    UnityGI o_gi;
    ResetUnityGI(o_gi);
    // Base pass with Lightmap support is responsible for handling ShadowMask / blending here for performance reason
    #if defined(HANDLE_SHADOWS_BLENDING_IN_GI)

这个宏定义必须满足两个条件:

// Shadowmap helpers.
#if defined( SHADOWS_SCREEN ) && defined( LIGHTMAP_ON )
    #define HANDLE_SHADOWS_BLENDING_IN_GI 1
#endif

必须开启屏幕阴影和有光照贴图
也就是说,必须有,这两个变体:

#pragma multi_compile _ LIGHTMAP_ON 
#pragma multi_compile _ SHADOWS_SCREEN
#if defined(HANDLE_SHADOWS_BLENDING_IN_GI)
        half bakedAtten = UnitySampleBakedOcclusion(data.lightmapUV.xy, data.worldPos); //从shadowmask上采样,烘焙遮挡信息
// Used by the forward rendering path
fixed UnitySampleBakedOcclusion (float2 lightmapUV, float3 worldPos)
{
    #if defined (SHADOWS_SHADOWMASK)

SHADOWS_SHADOWMASK这个宏打开的时机:

1)、定义#pragma multi_compile _ SHADOWS_SHADOWMASK

2)、使用ShadowMask烘焙模式,使用这个烘焙模式的时候:

unity摄像机窗口怎么调出来_#endif


3)、灯光必须设置为Mixed模式

这样关键字就打开了。
轻易不要使用:#pragma multi_compile_fwdbase 因为编译出的变体太多

// Used by the forward rendering path
fixed UnitySampleBakedOcclusion (float2 lightmapUV, float3 worldPos)
{
    #if defined (SHADOWS_SHADOWMASK)
 		#if defined (SHADOWS_SHADOWMASK)
	        #if defined(LIGHTMAP_ON)
	            fixed4 rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);  //从shadowmask上采样,烘焙遮挡信息
	        #else
	           ……
	        #endif
	        return saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector));

rawOcclusionMask为fixed4,记录的是该像素,被灯光影响的情况,比如采样的是(1,1,0,1)那么表示这个像素,被0号和1、3号灯照射到了,但是2号灯,不能照射到。这是原始的遮挡信息,所以是rawOcclusionMask——字面的意思是原始遮挡遮罩。

最后返回使用了一个dot(rawOcclusionMask, unity_OcclusionMaskSelector);
这个值是多少呢?
这个是灯光的编号,所谓的灯光的编号参考:
shadowmask的使用说明,在上面的这个博客里面。
比如有两个灯光,进行shadowmask进行烘焙,然后pass中有两个:base和add,那么主灯在base中渲染,然后副灯在add中渲染,此时的这个值:unity_OcclusionMaskSelector分别是:(1,0,0,0)和(0,1,0,0)。

unity摄像机窗口怎么调出来_#endif_02


unity摄像机窗口怎么调出来_#pragma_03


unity摄像机窗口怎么调出来_#pragma_04


unity摄像机窗口怎么调出来_unity摄像机窗口怎么调出来_05


unity摄像机窗口怎么调出来_unity摄像机窗口怎么调出来_06

ok,可以看到第5个灯,没有参与计算,因为第五个灯,在烘焙的时候,默认被弄成baked模式了。这个你改变成重要的灯,或者是设置最大的像素灯个数,也是不起作用的。

unity摄像机窗口怎么调出来_#pragma_07


unity摄像机窗口怎么调出来_#pragma_08

还有一个注意点,就是当一个pass没有标记为base或者add的时候,说明这个物体只会被绘制一次,那么选取的哪个灯进行绘制呢?
unity会选取一个最重要的灯进行绘制。这里怎么确定哪个是最重要的,unity是通过灯光的强度进行判断,比如我们将以下的shader:

Shader "Unlit/OcclusionMaskSelector"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
			//Tags{ "LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
			#pragma multi_compile _ LIGHTMAP_ON 
			#pragma multi_compile _ SHADOWS_SCREEN 
			#pragma multi_compile _ SHADOWS_SHADOWMASK

            #include "UnityCG.cginc"
			#include "UnityShadowLibrary.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
				float2 uv2 : TEXCOORD1;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
				float2 lightmapUV : TEXCOORD1;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				o.lightmapUV = v.uv2.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				#if defined (SHADOWS_SHADOWMASK)
					#if defined(LIGHTMAP_ON)
						fixed4 rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, i.lightmapUV.xy);
						//return rawOcclusionMask;
						return fixed4(saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector)),0,0,1);
						//return fixed4(0, 0, 1, 1);
					#else	
						return fixed4(0, 1, 0, 1);
					#endif
				#else
					return fixed4(1, 1, 0, 1);
				#endif
            }
            ENDCG
        }

//		Pass
//		{
//			Tags{ "LightMode" = "ForwardAdd"}
//			CGPROGRAM
//			#pragma vertex vert
//			#pragma fragment frag
//			#pragma multi_compile _ LIGHTMAP_ON 
//			#pragma multi_compile _ SHADOWS_SCREEN 
//			#pragma multi_compile _ SHADOWS_SHADOWMASK
//
//			#include "UnityCG.cginc"
//			#include "UnityShadowLibrary.cginc"
//			struct appdata
//			{
//				float4 vertex : POSITION;
//				float2 uv : TEXCOORD0;
//				float2 uv2 : TEXCOORD1;
//			};
//
//			struct v2f
//			{
//				float2 uv : TEXCOORD0;
//				float4 vertex : SV_POSITION;
//				float2 lightmapUV : TEXCOORD1;
//			};
//
//			v2f vert(appdata v)
//			{
//				v2f o;
//				o.vertex = UnityObjectToClipPos(v.vertex);
//				o.uv = v.uv;
//				o.lightmapUV = v.uv2.xy * unity_LightmapST.xy + unity_LightmapST.zw;
//				return o;
//			}
//
//			fixed4 frag(v2f i) : SV_Target
//			{
//				#if defined (SHADOWS_SHADOWMASK)
//					#if defined(LIGHTMAP_ON)
//						fixed4 rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, i.lightmapUV.xy);
//			//return rawOcclusionMask;
//			return fixed4(saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector)),0,0,1);
//			//return fixed4(0, 0, 1, 1);
//		#else	
//			return fixed4(0, 1, 0, 1);
//		#endif
//	#else
//		return fixed4(1, 1, 0, 1);
//	#endif
//}
//ENDCG
//}

    }
}

只保留一个pass,然后进行灯光强度的调整:

unity摄像机窗口怎么调出来_unity摄像机窗口怎么调出来_09


而如果调整另外一个灯的强度之后,调整到很大:

unity摄像机窗口怎么调出来_#endif_10


那么此时这个unity_OcclusionMaskSelector就会变化,变成那个最强灯的编号了。

ok,我们总结下,就是说,unity会自动的进行筛选最强的灯,这个unity_OcclusionMaskSelector就记录对应的灯的编号而已。不可能同时有(1,1,0,0)等两个同时为1的情况,只会有一个为1。

计算当前点到摄像机的距离:

float zDist = dot(_WorldSpaceCameraPos - data.worldPos, UNITY_MATRIX_V[2].xyz);
float fadeDist = UnityComputeShadowFadeDistance(data.worldPos, zDist);
data.atten = UnityMixRealtimeAndBakedShadows(data.atten, bakedAtten, UnityComputeShadowFade(fadeDist));
//这里的data.atten在哪里计算的???
float UnityComputeShadowFadeDistance(float3 wpos, float z)
{
    float sphereDist = distance(wpos, unity_ShadowFadeCenterAndType.xyz);
    return lerp(z, sphereDist, unity_ShadowFadeCenterAndType.w);
}

这个参考:

UnityStandardCore——》FragmentGI

d.atten = atten; //d是:UnityGIInput

fragForwardBaseInternal
UNITY_LIGHT_ATTENUATION(atten, i, s.posWorld);

#ifdef DIRECTIONAL
#   define UNITY_LIGHT_ATTENUATION(destName, input, worldPos) fixed destName = UNITY_SHADOW_ATTENUATION(input, worldPos);
#endif
if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE) || UNITY_LIGHT_PROBE_PROXY_VOLUME)
	#define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord.xy, worldPos, UNITY_READ_SHADOW_COORDS(a))
#else
	#define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord.xy, 0, 0)
#endif
half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos)
{
    //fade value
    float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);
    float fadeDist = UnityComputeShadowFadeDistance(worldPos, zDist);
    half  realtimeToBakedShadowFade = UnityComputeShadowFade(fadeDist);
    
	//baked occlusion if any
    half shadowMaskAttenuation = UnitySampleBakedOcclusion(lightmapUV, worldPos);

	half realtimeShadowAttenuation = 1.0f;
    //directional realtime shadow
    #if defined (SHADOWS_SCREEN)
        #if defined(UNITY_NO_SCREENSPACE_SHADOWS) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)
            realtimeShadowAttenuation = unitySampleShadow(mul(unity_WorldToShadow[0], unityShadowCoord4(worldPos, 1)));
        #else
            //Only reached when LIGHTMAP_ON is NOT defined (and thus we use interpolator for screenPos rather than lightmap UVs). See HANDLE_SHADOWS_BLENDING_IN_GI below.
            realtimeShadowAttenuation = unitySampleShadow(screenPos);
        #endif
    #endif
half UnityComputeShadowFade(float fadeDist)
{
    return saturate(fadeDist * _LightShadowData.z + _LightShadowData.w);
}
// ---- Screen space direction light shadows helpers (any version)
#if defined (SHADOWS_SCREEN)

    #if defined(UNITY_NO_SCREENSPACE_SHADOWS)
        UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
        #define TRANSFER_SHADOW(a) a._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) );
        inline fixed unitySampleShadow (unityShadowCoord4 shadowCoord)
        {
            #if defined(SHADOWS_NATIVE)
                fixed shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, shadowCoord.xyz);
                shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
                return shadow;
            #else
                unityShadowCoord dist = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, shadowCoord.xy);
                // tegra is confused if we use _LightShadowData.x directly
                // with "ambiguous overloaded function reference max(mediump float, float)"
                unityShadowCoord lightShadowDataX = _LightShadowData.x;
                unityShadowCoord threshold = shadowCoord.z;
                return max(dist > threshold, lightShadowDataX);
            #endif
        }

    #else // UNITY_NO_SCREENSPACE_SHADOWS
        UNITY_DECLARE_SCREENSPACE_SHADOWMAP(_ShadowMapTexture);
        #define TRANSFER_SHADOW(a) a._ShadowCoord = ComputeScreenPos(a.pos);
        inline fixed unitySampleShadow (unityShadowCoord4 shadowCoord)
        {
            fixed shadow = UNITY_SAMPLE_SCREEN_SHADOW(_ShadowMapTexture, shadowCoord);
            return shadow;
        }

    #endif

    #define SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
    #define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
#endif