文章目录
- 前言
- 一、GI中 间接光照的实现
- 1、看Unity的源码可知,在计算GI的间接光照时,最主要的实现是在UnityGI_Base函数中
- 二、分析 UnityGI_Base 中实现的功能
- 1、ResetUnityGI的作用
- 2、第一个#if中实现的功能:计算在Distance Shadowmask 中实时阴影与烘培阴影的混合过程
- 3、第二个#if中实现的功能:计算使用球谐光照(当使用光照探针后的效果)
- 4、第三个#if中实现的功能:计算静态 GI (当使用BackedGI后的效果)
- 5、第四个#if中实现的功能:计算动态 GI (当使用RealtimeGI后的效果)
前言
Unity中Shader的GI的间接光实现。在上一篇文章中,我们实现了GI中的直接光。但是,Global Illumination 是由 直接光 加 间接光 后的结果,所以我们还需要准备 GI 中的间接光。
- Unity中Shader的GI的直接光实现
一、GI中 间接光照的实现
1、看Unity的源码可知,在计算GI的间接光照时,最主要的实现是在UnityGI_Base函数中
UnityGI_Base如下:
inline UnityGI UnityGI_Base1(UnityGIInput data, half occlusion, half3 normalWorld)
{
UnityGI o_gi;
ResetUnityGI1(o_gi);
// Base pass with Lightmap support is responsible for handling ShadowMask / blending here for performance reason
#if defined(HANDLE_SHADOWS_BLENDING_IN_GI)
half bakedAtten = UnitySampleBakedOcclusion(data.lightmapUV.xy, data.worldPos);
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));
#endif
o_gi.light = data.light;
o_gi.light.color *= data.atten;
#if UNITY_SHOULD_SAMPLE_SH
o_gi.indirect.diffuse = ShadeSHPerPixel(normalWorld, data.ambient, data.worldPos);
#endif
#if defined(LIGHTMAP_ON)
// Baked lightmaps
half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);
half3 bakedColor = DecodeLightmap(bakedColorTex);
#ifdef DIRLIGHTMAP_COMBINED
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
o_gi.indirect.diffuse += DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
ResetUnityLight(o_gi.light);
o_gi.indirect.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap (o_gi.indirect.diffuse, data.atten, bakedColorTex, normalWorld);
#endif
#else // not directional lightmap
o_gi.indirect.diffuse += bakedColor;
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
ResetUnityLight(o_gi.light);
o_gi.indirect.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap(o_gi.indirect.diffuse, data.atten, bakedColorTex, normalWorld);
#endif
#endif
#endif
#ifdef DYNAMICLIGHTMAP_ON
// Dynamic lightmaps
fixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, data.lightmapUV.zw);
half3 realtimeColor = DecodeRealtimeLightmap (realtimeColorTex);
#ifdef DIRLIGHTMAP_COMBINED
half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
o_gi.indirect.diffuse += DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normalWorld);
#else
o_gi.indirect.diffuse += realtimeColor;
#endif
#endif
o_gi.indirect.diffuse *= occlusion;
return o_gi;
}
所以我们在片元着色器中可以直接给 gi 赋值,不使用 LightingLambert_GI1函数
gi = UnityGI_Base1(giInput,1,o.Normal);
可以看出,效果是一样的:
二、分析 UnityGI_Base 中实现的功能
1、ResetUnityGI的作用
由图可见:这个 ResetUnityGI1 函数的作用是和之前初始化的函数 UNITY_INITIALIZE_OUTPUT 功能一样的。
然后,除掉 #if 的部分,主要实现了以下功能。
2、第一个#if中实现的功能:计算在Distance Shadowmask 中实时阴影与烘培阴影的混合过程
3、第二个#if中实现的功能:计算使用球谐光照(当使用光照探针后的效果)
4、第三个#if中实现的功能:计算静态 GI (当使用BackedGI后的效果)
光照图的采样(核心部分)
之后这个功能是在Unity中开启 定向光 模式时使用
5、第四个#if中实现的功能:计算动态 GI (当使用RealtimeGI后的效果)