【光照】UnityURP中的[HDR贴图]
【从UnityURP开始探索游戏渲染】专栏-直达
HDR贴图的概念与特性
HDR(高动态范围)贴图是Unity URP中用于存储超出标准0-1范围光照信息的特殊纹理格式。与普通LDR(低动态范围)贴图相比,HDR贴图能够存储更广范围的亮度值,通常使用16位或32位浮点精度而非8位整数精度。
HDR贴图主要分为两类:
- HDR环境贴图:用于天空盒和环境光照,通常采用.hdr或.exr格式
- HDR光照贴图:用于烘焙光照信息,存储间接光照数据
HDR贴图解决的问题
亮度范围限制:
- 传统LDR贴图只能表示0-1范围的亮度值,无法准确表现真实世界的光照强度(如阳光直射可能达到100,000尼特)。
细节丢失:
- LDR在高亮区域会产生过曝,丢失细节;在暗部则会产生噪点和色带。
光照计算精度:
- HDR贴图提供更高精度的光照数据,使后期处理(如Bloom、色调映射)效果更自然。
URP中HDR贴图的具体使用
导入HDR环境贴图
csharp
// 通过代码加载HDR贴图
public class HDRLoader : MonoBehaviour {
public Texture2D hdrTexture;
void Start() {
// 设置HDR贴图为天空盒
RenderSettings.skybox.SetTexture("_MainTex", hdrTexture);
}
}
配置HDR天空盒
- 下载HDR贴图(推荐HDRI Hub等资源网站)
- 导入Unity项目,确保纹理导入设置中"Texture Shape"设为Cube
- 创建材质,选择Shader > Skybox > Cubemap
- 将HDR贴图拖入材质
- 在Lighting窗口中将材质指定为天空盒
烘焙HDR光照贴图
- 确保场景物体:
- 具有Mesh Renderer组件
- 标记为Contribute GI
- 启用了Generate Lightmap UVs
- 在Lighting窗口调整Lightmap Resolution和Scale In Lightmap参数
- 关闭自动烘焙,手动执行烘焙以获得最佳效果
HDR贴图的高级应用
Light Cookies:
- 使用HDR贴图作为2D遮罩或立方体贴图,控制光源形状和衰减
- HDR贴图作为Light Cookies可以精确控制光源的形状和衰减特性,相比普通LDR贴图能够表现更广范围的亮度值,特别适合模拟高亮度光源效果如聚光灯、霓虹灯等。URP中支持两种形式的Cookies:
- 2D平面贴图:主要用于聚光灯(Spot Light)
- 立方体贴图:主要用于点光源(Point Light)
2D HDR Cookie实现过程
-
准备HDR贴图
csharp // 创建HDR纹理 Texture2D hdrCookie = new Texture2D(512, 512, TextureFormat.RGBAHalf, true); hdrCookie.wrapMode = TextureWrapMode.Clamp; hdrCookie.filterMode = FilterMode.Bilinear;
-
应用到聚光灯
csharp public class SpotLightCookieSetter : MonoBehaviour { public Texture2D hdrCookieTexture; public Light spotLight; void Start() { if(spotLight.type == LightType.Spot) { spotLight.cookie = hdrCookieTexture; spotLight.cookieSize = 10f;// 控制Cookie影响范围 } } }
-
材质设置
在URP中需要确保材质使用支持HDR的Shader,如Universal Render Pipeline/Lit。
立方体HDR Cookie实现过程
- 创建HDR立方体贴图
csharp
// 通过代码生成HDR立方体贴图
public Cubemap CreateHDRCubemap(int size) {
Cubemap hdrCubemap = new Cubemap(size, TextureFormat.RGBAHalf, true);
// 填充各面数据...return hdrCubemap;
}
- 应用到点光源
csharp
public class PointLightCookieSetter : MonoBehaviour {
public Cubemap hdrCubemap;
public Light pointLight;
void Start() {
if(pointLight.type == LightType.Point) {
pointLight.cookie = hdrCubemap;
}
}
}
-
完整示例:HDR Cookie光照场景
-
HDRCookieDemo.cs
using UnityEngine; using UnityEngine.Rendering.Universal; public class HDRCookieDemo : MonoBehaviour { public Texture2D spotCookie; public Cubemap pointCookie; public Light spotLight; public Light pointLight; void Start() { // 设置聚光灯Cookie spotLight.type = LightType.Spot; spotLight.cookie = spotCookie; spotLight.cookieSize = 8f; // 设置点光源Cookie pointLight.type = LightType.Point; pointLight.cookie = pointCookie; // 确保使用HDR spotLight.useColorTemperature = true; pointLight.useColorTemperature = true; } }
-
关键参数调整
- 亮度控制:HDR Cookie的亮度值可以超过1.0,实现超亮光源效果
- 衰减调节:通过Cookie的边缘渐变控制光源衰减
- 色彩范围:HDR支持更广的色域表现
性能优化建议
- 合理控制HDR Cookie分辨率(通常512x512足够)
- 对远处光源使用较低分辨率Cookie
- 考虑使用压缩的HDR格式(如BC6H)减少内存占用
- 动态加载和卸载HDR Cookie资源
反射探针:
-
生成HDR立方体贴图用于高质量反射
-
HDR反射探针通过捕获场景环境生成高动态范围立方体贴图,为物体提供更真实的反射效果。相比传统LDR反射贴图,HDR立方体贴图能够存储更广范围的亮度值(0-65504),保留亮部和暗部细节,特别适合表现金属、玻璃等高反射材质。
-
创建并配置反射探针
csharp // 创建反射探针并设置HDR属性 GameObject probeObj = new GameObject("HDR_ReflectionProbe"); ReflectionProbe probe = probeObj.AddComponent<ReflectionProbe>(); probe.mode = ReflectionProbeMode.Realtime; probe.hdr = true;// 启用HDR probe.resolution = 512;// 分辨率 probe.shadowDistance = 50f;// 阴影距离 probe.cullingMask = LayerMask.GetMask("Default");// 渲染层 probe.boxProjection = true;// 启用盒投影
-
烘焙HDR立方体贴图
csharp // 手动触发烘焙 IEnumerator BakeHDRProbe(ReflectionProbe probe) { probe.RenderProbe(); while(probe.IsFinishedRendering(probe.GetInstanceID()) == false) { yield return null; } Debug.Log("HDR Cubemap烘焙完成"); }
-
在Shader中采样HDR反射贴图
glsl // URP Shader中采样HDR反射探针 half3 SampleHDRReflection(float3 worldPos, float3 worldNormal) { float3 reflectDir = reflect(-_WorldSpaceCameraPos.xyz, worldNormal); half4 encodedCubemap = SAMPLE_TEXTURECUBE(unity_SpecCube0, samplerunity_SpecCube0, reflectDir); half3 decodedColor = DecodeHDREnvironment(encodedCubemap, unity_SpecCube0_HDR); return decodedColor; }
完整示例
-
HDRReflectionDemo.cs
using UnityEngine; using UnityEngine.Rendering.Universal; public class HDRReflectionDemo : MonoBehaviour { public Material reflectiveMaterial; public Light directionalLight; void Start() { // 1. 创建HDR反射探针 var probeObj = new GameObject("HDR_Probe"); var probe = probeObj.AddComponent<ReflectionProbe>(); probe.size = new Vector3(20, 20, 20); probe.hdr = true; probe.resolution = 1024; // 2. 设置反射材质参数 reflectiveMaterial.SetFloat("_Metallic", 1.0f); reflectiveMaterial.SetFloat("_Smoothness", 0.95f); // 3. 动态更新反射探针 StartCoroutine(UpdateProbe(probe)); } IEnumerator UpdateProbe(ReflectionProbe probe) { while(true) { probe.RenderProbe(); while(!probe.IsFinishedRendering(probe.GetInstanceID())) { yield return null; } yield return new WaitForSeconds(1f); // 每秒更新一次 } } }
关键参数优化建议
- 分辨率选择:根据目标平台性能选择256-2048分辨率,移动端建议512
- 更新频率:实时探针可选择"Via Scripting"模式按需更新
- 盒投影:室内场景务必启用Box Projection实现距离相关反射
- 混合距离:多个探针间设置Blend Distance实现平滑过渡
- HDR解码:确保Shader中正确使用DecodeHDREnvironment函数处理HDR数据
性能优化
- 对静态物体使用Baked模式探针,动态物体使用Realtime模式
- 通过Importance属性控制多个探针的混合权重
- 使用Time Slicing分散探针更新负载
- 合理设置Culling Mask避免渲染不必要对象
- 移动平台可降低HDR精度至R11G11B10格式
全局光照:
-
HDR贴图提供更精确的间接光照计算基础
-
准备HDR环境贴图
首先需要获取HDR环境贴图(.hdr或.exr格式),推荐从HDRI Hub等资源网站下载高质量的HDR天空盒贴图。导入Unity后需将纹理类型设置为"Cube"并启用HDR选项:
csharp // 通过代码验证HDR贴图设置 void CheckHDREnvironment(Texture2D hdrTexture) { if(hdrTexture.format != TextureFormat.RGBAHalf) { Debug.LogError("请使用HDR格式贴图(RGBAHalf)"); } }
-
配置HDR全局光照
- 在URP渲染管线中设置HDR环境光:
csharp public class HDRGlobalIllumination : MonoBehaviour { public Cubemap hdrCubemap; public Material skyboxMaterial; void Start() { // 设置HDR天空盒 RenderSettings.skybox = skyboxMaterial; skyboxMaterial.SetTexture("_Tex", hdrCubemap); // 启用HDR全局光照 RenderSettings.ambientMode = AmbientMode.Skybox; DynamicGI.UpdateEnvironment(); } }
-
烘焙HDR光照贴图
-
确保场景静态物体:
- 具有Mesh Renderer组件
- 标记为Contribute GI
- 启用了Generate Lightmap UVs
-
在Lighting窗口设置:
csharp Lightmapping.lightingSettings.lightmapResolution = 40;// 每单位分辨率 Lightmapping.lightingSettings.lightmapper = Lightmapper.ProgressiveGPU; Lightmapping.lightingSettings.filteringMode = LightmapFiltering.Advanced;
-
执行烘焙:
csharp Lightmapping.BakeAsync();// 异步烘焙避免卡顿
-
材质Shader适配
-
在URP Lit Shader中增强HDR间接光采样:
glsl // 在URP Shader中增加HDR间接光处理 half3 SampleHDRIndirectLight(float3 worldPos, float3 normal) { half3 indirectDiffuse = SampleSH9(normal); // 球谐光照 half4 encodedCubemap = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflect(-worldPos, normal), 0); half3 decodedColor = DecodeHDREnvironment(encodedCubemap, unity_SpecCube0_HDR); return indirectDiffuse * 0.5 + decodedColor * 0.5; // 混合光照 }
实时更新策略
-
对于动态物体,结合光照探针和反射探针:
csharp public class DynamicHDRGI : MonoBehaviour { public ReflectionProbe hdrProbe; public LightProbeGroup lightProbes; void Update() { // 每2秒更新一次探针 if(Time.frameCount % 120 == 0) { hdrProbe.RenderProbe(); LightProbes.Tetrahedralize(); } } }
性能优化
- 静态物体使用烘焙光照贴图,动态物体使用HDR光照探针
- 根据距离分级使用不同分辨率的HDR贴图(近处1024,远处256)
- 使用BC6H压缩格式减少HDR贴图内存占用
- 通过脚本控制探针更新频率避免性能峰值
性能优化建议
- 合理控制HDR贴图分辨率,平衡质量与性能
- 移动平台考虑使用压缩的HDR格式(如ASTC HDR)
- 对远处或小物体使用较低分辨率的HDR光照贴图
- 动态加载和卸载HDR贴图以管理内存
HDR贴图是URP实现高质量渲染的重要工具,正确使用可以显著提升场景的真实感和视觉冲击力
【从UnityURP开始探索游戏渲染】专栏-直达 (欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)