Global Bake
这里是简化Lighting.cginc的UnityGI_Base函数
以及AutoLight.cginc的LightingLambert
来实现bake贴图采样(没开灯光)
其中,Mixed是重点
Directional Mode是重点
Light组件的Mode需要调成Mixed
完成以上内容可以在使用unity标准Shader的情况下看的bake情况
自定义cginc文件
直接看pass
Baked光照贴图采样技术
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//需要使用这两个宏定义
#pragma multi_compile DIRLIGHTMAP_COMBINED
#pragma multi_compile LIGHTMAP_ON
#include "UnityCG.cginc"
#include "CGINC/MyCGInc.cginc"
struct appdata
{
float4 vertex : POSITION;
#if defined(LIGHTMAP_ON)
float4 texcoord1 : TEXCOORD1;
#endif
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : NORMAL;
float3 worldPos : TEXCOORD0;
#if defined(LIGHTMAP_ON)
fixed4 lightmapUV : TEXCOORD1;
#endif
};
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(unity_ObjectToWorld, v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
#if defined(LIGHTMAP_ON)
o.lightmapUV.xy = v.texcoord1 * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target
{
SurfaceOutput o;
UNITY_INITIALIZE_OUTPUT(SurfaceOutput, o);
o.Albedo = 1;
o.Normal = i.worldNormal;
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.light.color = _LightColor0;
gi.light.dir = _WorldSpaceLightPos0;
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = i.worldPos;
giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
giInput.atten = 0.5;//先默认给一个,后续需要计算光照衰减
#if defined(LIGHTMAP_ON)
giInput.lightmapUV = i.lightmapUV;
#endif
//对烘焙贴图进行采样
UnityGI_Base(giInput,1.0h,i.worldNormal, gi);
//计算一个简单的Lambert光照模型
return LightingLambert(o, gi);
}
ENDCG
}
这些gi啊giInput啊什么什么的,都来根据Unity内部实现使用的
来自于Lighting.cginc
同时,自定义的cginc文件也是改编自Lighting.cginc
1.SurfaceOutput是Lighting.cginc定义的struct,我们可以在自定义cginc中也定义一个
这里我定义了一个简略版,就是把需要的数据留着,不用的就删了
2.UnityGI和UnityGIInput也都是struct,由于东西太多,我这使用的#include "UnityLightingCommon.cginc"
这样,该cginc和该pass就可以使用这两个struct了
3.LightingLambert来自于Lighting.cginc,是实现一个简单的Lambert光照模型
4.UnityGI_Base来自于Lighting.cginc引入的UnityGlobalIllumination.cginc
这里使用的是改编版,只留下了一个宏定义
UnityGI_Base原版
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)
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;
}
我看着就是一个简单的bake贴图采样,不过和法线有关
MyCGInc.cginc
#ifndef MYCGINC_CGINCLUDE
#define MYCGINC_CGINCLUDE
#include "UnityLightingCommon.cginc"
struct SurfaceOutput {
fixed3 Albedo;
fixed3 Normal;
};
inline fixed4 LightingLambert (SurfaceOutput s, UnityGI gi)
{
fixed4 c;
fixed diff = max (0, dot (s.Normal, gi.light.dir));
c.rgb = s.Albedo * gi.light.color * diff;
#if defined(LIGHTMAP_ON)
c.rgb += s.Albedo * gi.indirect.diffuse;
#endif
return c;
}
inline void UnityGI_Base(UnityGIInput data, half occlusion, half3 normalWorld, inout UnityGI gi)
{
#if defined(LIGHTMAP_ON)
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);
gi.indirect.diffuse += DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);
#endif
#endif
//将衰减应用于灯光颜色在
gi.light.color *= data.atten;
//环境光遮蔽
gi.indirect.diffuse *= occlusion;
}
#endif
Global Bake之Non-Directional
近距离采用实时阴影,远距离采用Baked阴影 的技术
1.Light组件的Mode需要调成Mixed
2.Bake设置的LightingMode要调成Shadowmask
3.Bake设置的Directional Mode要调成Non-Directional
4.ProjectSettings-Quality-Shadows-Shadowmask Mode要调成Distance Shadowmask
5.ProjectSettings-Quality-Shadows-ShadowDistance调成你想要的值,这里是 5
效果:Bake的光照PosY是30,实时的光照PosY调了个46
距离小于ShadowDistance就用的实时阴影,大于就用bake阴影
此时上面是实时,下面是bake
继续远离
代码部分:
原先的自定义cginc没有实现该技术
该技术来自于UnityGlobalIllumination.cginc的HANDLE_SHADOWS_BLENDING_IN_GI宏定义,
就是将自定义cginc,修改成了使用Lighting.cginc的Bake阴影技术和AutoLight.cginc的实时阴影技术
代码部分
主pass
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct appdata
{
float4 vertex : POSITION;
#if defined(LIGHTMAP_ON)
float4 texcoord1 : TEXCOORD1;
#endif
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : NORMAL;
float3 worldPos : TEXCOORD0;
#if defined(LIGHTMAP_ON)
fixed4 lightmapUV : TEXCOORD1;
#endif
UNITY_LIGHTING_COORDS(2,3)
};
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(unity_ObjectToWorld, v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
#if defined(LIGHTMAP_ON)
o.lightmapUV.xy = v.texcoord1 * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
UNITY_TRANSFER_LIGHTING(o, v.texcoord1.xy);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
SurfaceOutput o;
UNITY_INITIALIZE_OUTPUT(SurfaceOutput, o);
o.Albedo = 1;
o.Normal = i.worldNormal;
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.light.color = _LightColor0;
gi.light.dir = _WorldSpaceLightPos0;
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = i.worldPos;
giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
giInput.atten = atten;
#if defined(LIGHTMAP_ON) || defined(DYNAMACLIGHTMAP_ON)
giInput.lightmapUV = i.lightmapUV;
#endif
//对烘焙贴图进行采样
LightingLambert_GI(o,giInput,gi);
//计算一个简单的Lambert光照模型
return LightingLambert(o, gi);
}
ENDCG
}
阴影Pass
pass
{
Tags{ "LightMode"="ShadowCaster" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct a2v
{
float4 vertex: POSITION;
half3 normal: NORMAL;
};
struct v2f
{
V2F_SHADOW_CASTER;
};
v2f vert(a2v v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i);
}
ENDCG
}