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烘焙模式,使用这个烘焙模式的时候:
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)。
ok,可以看到第5个灯,没有参与计算,因为第五个灯,在烘焙的时候,默认被弄成baked模式了。这个你改变成重要的灯,或者是设置最大的像素灯个数,也是不起作用的。
还有一个注意点,就是当一个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_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