1. URP光照贴图Shader核心原理剖析
光照贴图(Lightmap)是Unity中实现高质量静态光照的核心技术,它通过预计算场景中的光线反弹信息,将光照结果烘焙到纹理中,从而在运行时实现逼真光照效果而不产生实时计算开销。在URP(Universal Render Pipeline)中,光照贴图的实现与传统内置管线有显著差异,主要体现在Shader编写和光照数据处理方式上。
URP的光照贴图系统基于以下技术栈:
- 光照贴图编码:采用RGBM或HDR编码存储高动态范围光照数据
- 间接光采样:通过Unity内置的
unity_Lightmap和unity_LightmapInd纹理获取烘焙结果 - 光照探针融合:动态物体通过光照探针与静态光照贴图混合
- Shadowmask:处理静态阴影与动态阴影的混合关系
关键提示:URP 7.0+版本后,光照贴图采样接口有重大变更,传统
SAMPLE_LIGHTMAP宏已被废弃,需使用新的SampleLightmap函数。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. URP光照贴图Shader实现详解
2.1 基础Shader结构
URP中支持光照贴图的Shader需要包含以下核心部分:
hlsl复制Shader "Custom/LightmapExample"
{
Properties
{
_MainTex ("Base Map", 2D) = "white" {}
[NoScaleOffset] _LightMap ("Lightmap", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode"="UniversalForward" }
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"
ENDHLSL
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float2 lightmapUV : TEXCOORD1;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float2 lightmapUV : TEXCOORD1;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
output.lightmapUV = input.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
return output;
}
half4 frag(Varyings input) : SV_Target
{
half4 baseColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
// 新版URP光照贴图采样方式
half3 bakedLight = SampleLightmap(input.lightmapUV);
return half4(baseColor.rgb * bakedLight, baseColor.a);
}
ENDHLSL
}
}
}
2.2 光照贴图采样优化技巧
在实际项目中,光照贴图采样需要考虑多种优化策略:
- Mipmap处理:
hlsl复制// 根据像素到摄像机的距离动态选择mip级别
float mipLevel = CalculateMipLevel(input.lightmapUV);
half3 bakedLight = SampleLightmap(input.lightmapUV, mipLevel);
- 方向性光照贴图:
hlsl复制half4 bakedData = SAMPLE_TEXTURE2D(unity_LightmapInd, samplerunity_Lightmap, input.lightmapUV);
half3 normalTS = UnpackNormal(bakedData.xyz);
half3 diffuse = bakedData.w * mainLight.color;
- Shadowmask混合:
hlsl复制half shadowAttenuation = SampleShadowmask(input.lightmapUV);
half3 finalLight = bakedLight * shadowAttenuation;
3. 常见问题解决方案
3.1 光照贴图显示异常排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 模型表面全黑 | 未生成光照贴图 | 检查Window > Rendering > Lighting设置并重新烘焙 |
| 光照贴图闪烁 | UV重叠或精度不足 | 调整模型第二套UV,确保无重叠且展开合理 |
| 颜色过曝 | RGBM解码错误 | 检查Shader中是否正确定义DECODE_LIGHTMAP宏 |
| 动态物体无光照 | 未设置光照探针 | 在Lighting窗口中配置光照探针组 |
| 阴影显示异常 | Shadowmask模式配置错误 | 检查Project Settings > Graphics > Lightmap Modes |
3.2 性能优化实战经验
-
纹理压缩设置:
- 将光照贴图设置为ASTC 6x6压缩格式
- 在Quality Settings中调整Lightmap Compression为High Quality
-
Shader变体控制:
hlsl复制#pragma shader_feature _LIGHTMAP_SHADOW_MIXING
#pragma shader_feature _DIRLIGHTMAP_COMBINED
- 动态合批优化:
- 确保使用相同材质和光照贴图的物体满足合批条件
- 在URP Asset中开启Dynamic Batching选项
4. 高级应用技巧
4.1 光照贴图与实时GI混合
在需要部分动态光照的场景中,可以混合使用烘焙光照和实时GI:
hlsl复制half3 realtimeGI = SampleSH(input.normalWS);
half3 mixedLighting = lerp(bakedLight, realtimeGI, _DynamicLightRatio);
4.2 自定义光照贴图通道
通过扩展Shader,可以实现特殊效果的光照贴图应用:
hlsl复制// 在片元着色器中添加特效通道
half3 emissive = SAMPLE_TEXTURE2D(_EmissiveMap, sampler_EmissiveMap, input.uv).rgb;
half3 finalColor = (baseColor.rgb * bakedLight) + emissive;
4.3 移动端优化方案
针对移动平台的特定优化策略:
- 使用半分辨率光照贴图
- 禁用方向性光照贴图
- 采用更轻量的解码算法:
hlsl复制half3 DecodeLightmapMobile(half4 encoded) {
return encoded.rgb * (encoded.a * 4.0);
}
5. 工程实践建议
-
光照贴图UV处理规范:
- 确保第二套UV在0-1范围内且无重叠
- 复杂模型使用第三方UV展开工具
- 设置合理的Texel Density(通常15-30px/unit)
-
Shader调试技巧:
hlsl复制// 调试用可视化输出
return half4(input.lightmapUV.xxx, 1); // 查看UV分布
return half4(bakedLight, 1); // 查看原始光照数据
- 跨平台注意事项:
- 在Unity 2021 LTS中测试不同平台的光照贴图表现
- 针对WebGL平台需要特别测试光照贴图内存占用
- 对于Switch等主机平台,需验证BC6H压缩格式支持
在实际项目开发中,我发现光照贴图的质量80%取决于前期美术资源的规范准备。建议在项目初期就建立严格的光照贴图制作规范,包括模型UV2的检查流程、光照贴图分辨率的层级划分、以及Shader功能的标准接口定义。这能大幅减少后期因光照问题导致的返工。
