Shader随笔Baked&GI

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
}

自发光Bake Pass

源码:Unity-Built-in-Shaders/DefaultResourcesExtra/Illumin-VertexLit.shader at master · TwoTailsGames/Unity-Built-in-Shaders (github.com)

修改版

自发光BakePass
//只有bake才会走这个pass
pass
{
Name "Meta"
Tags { "LightMode"="Meta" }
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityMetaPass.cginc"
fixed4 _Color;
struct v2f
{
float4 pos: SV_POSITION;
};
v2f vert(appdata_full v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f,o);
o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST);
return o;
}
fixed4 frag(v2f i):SV_Target
{
UnityMetaInput metaIN;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
metaIN.Albedo = 1;
metaIN.Emission = _Color;
return UnityMetaFragment(metaIN);
}
ENDCG
}

然后需要修改本材质的Lightmap Flags

开启该物体的debug模式,在材质里找Lightmap Flags,设置为2

原因:MaterialGlobalIlluminationFlags - Unity 脚本 API

也可以在最后加上CustomEditor "LegacyIlluminShaderGUI"

posted @   被迫吃冰淇淋的小学生  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示