写在前面
在Unity中,天空盒(Skybox)不仅承担视觉上的背景作用,更是场景环境光照与氛围塑造的重要组成部分。不同时间、天气、场景转换等,都需要灵活调整天空的亮度。而**曝光度(Exposure)**就是其中最关键的调控参数之一。
本篇将带你从实战角度出发,构建一个Skybox曝光控制组件(SkyboxExposureController),支持:
- 内置渲染管线(Built-in)
 - 通用渲染管线(URP)
 - 高级渲染管线(HDRP)
 
最终实现一个跨平台、易拓展、实时可控的天空盒曝光调整方案。

一、Skybox曝光控制的实际意义
在游戏开发、VR仿真、影视预览等Unity项目中,我们往往需要模拟以下视觉效果:
| 场景 | 曝光度变化的意义 | 
|---|---|
| 日夜交替 | 白天亮、晚上暗 | 
| 天气系统 | 晴天曝光高,阴天低曝光 | 
| 剧情过渡 | 切换场景时通过渐变曝光实现氛围过渡 | 
| 剧情特写 | 聚焦主角时,压暗背景提高聚焦感 | 
这些都需要我们对天空盒的曝光参数进行精细控制,而由于Unity的不同渲染管线(Built-in / URP / HDRP)控制方式不同,往往给开发带来了困扰。因此,我们要做的第一件事就是——统一兼容性。
示例效果
- 曝光度:0.05

 - 曝光度:0.36

 - 曝光度:1.0

 
二、Unity三大渲染管线曝光控制机制对比
| 渲染管线 | 曝光控制方式 | 备注 | 
|---|---|---|
| 内置管线 | Skybox材质的 _Exposure 属性 | 默认Skybox Shader支持 | 
| URP | Volume中的Exposure组件 | 需设置为Fixed模式 | 
| HDRP | Volume中的HDRISky组件 | 通过 exposure.value 设置 | 
如你所见,三者在控制机制和接口上都不相同,因此要通过代码自动适配。
三、组件设计目标与亮点
我们要实现的 SkyboxExposureController 组件将具备以下特性:
- 自动识别当前渲染管线,无需手动配置;
 - Inspector面板可调节曝光值,并支持运行时动态生效;
 - 打包构建可用,不依赖 
UNITY_EDITOR宏; - 扩展性强,支持绑定曲线/Timeline进行动画控制;
 - Volume自动探测功能,降低用户配置门槛。
 
四、实现思路与核心技术
判断当前渲染管线
Unity 提供了以下宏定义用于区分当前渲染管线:
UNITY_RENDER_PIPELINE_UNIVERSAL
UNITY_RENDER_PIPELINE_HDRP
 
若都未定义,则说明使用的是内置渲染管线。
曝光控制逻辑实现
- 内置管线:通过 
RenderSettings.skybox.SetFloat("_Exposure", value)修改曝光; - URP:通过 Volume 的 
Exposure组件,设置其fixedExposure.value; - HDRP:通过 Volume 的 
HDRISky组件,设置其exposure.value。 
注意 URP/HDRP 都需事先启用 Volume 中的相关模块。
自动寻找 Volume(新增功能)
为提升用户体验,我们设计逻辑:当用户未设置 Volume 引用时,自动查找场景中第一个可用 Volume。
五、完整组件代码
using UnityEngine;
using UnityEngine.Rendering;
#if UNITY_RENDER_PIPELINE_HDRP
using UnityEngine.Rendering.HighDefinition;
#elif UNITY_RENDER_PIPELINE_UNIVERSAL
using UnityEngine.Rendering.Universal;
#endif[ExecuteAlways]
public class SkyboxExposureController : MonoBehaviour
{[Header("统一曝光值")][Range(0f, 5f)]public float exposure = 1.0f;[Header("URP / HDRP 使用的 Volume")]public Volume volume;#if UNITY_RENDER_PIPELINE_HDRPprivate HDRISky hdriSky;
#elif UNITY_RENDER_PIPELINE_UNIVERSALprivate Exposure urpExposure;
#endifprivate Material skyboxMaterial;void OnEnable(){if (volume == null)volume = FindObjectOfType<Volume>();skyboxMaterial = RenderSettings.skybox;#if UNITY_RENDER_PIPELINE_HDRPif (volume != null && volume.sharedProfile.TryGet(out hdriSky)){hdriSky.active = true;}
#elif UNITY_RENDER_PIPELINE_UNIVERSALif (volume != null && volume.sharedProfile.TryGet(out urpExposure)){urpExposure.active = true;}
#endif}void Update(){
#if UNITY_RENDER_PIPELINE_HDRPif (hdriSky != null){hdriSky.exposure.value = exposure;}
#elif UNITY_RENDER_PIPELINE_UNIVERSALif (urpExposure != null){urpExposure.fixedExposure.value = exposure;}
#elseif (skyboxMaterial != null && skyboxMaterial.HasProperty("_Exposure")){skyboxMaterial.SetFloat("_Exposure", exposure);}
#endif}
}
 
六、使用方法详解
1. 内置渲染管线
- 确保项目未启用SRP;
 - 将SkyboxExposureController挂载到任意场景对象;
 - 拖入RenderSettings中正在使用的Skybox材质;
 - 调整
exposure值,即可实时控制天空亮度。 
2. URP渲染管线
- 创建一个 Global Volume;
 - 添加 Exposure 模块,并设置为 Fixed 模式;
 - 将 SkyboxExposureController 脚本挂载至对象;
 - 拖入 Volume 引用,或让脚本自动查找;
 - 调整 
exposure数值观察效果。 
URP 关键点:Exposure必须为 Fixed模式 才会响应参数设置。
3. HDRP渲染管线
- 创建一个 Global Volume;
 - 添加 HDRISky 和 VisualEnvironment 模块;
 - 将 Sky Type 设置为 HDRI;
 - 设置 Exposure 值为可变;
 - 同样添加脚本并拖入 Volume。
 
HDRP中
HDRISky.exposure.value才是真正控制天空亮度的关键。
七、进阶用法:曲线控制曝光变化
为了实现如“日夜循环”般动态变化,我们可增加如下扩展:
[Header("曝光曲线控制")]
public bool useCurve;
public AnimationCurve exposureCurve;
public float time;void Update()
{if (useCurve){exposure = exposureCurve.Evaluate(time);time += Time.deltaTime;}// ...原有曝光设置逻辑
}
 
也可以使用 Timeline 控制 exposure 属性,实现导演级画面过渡。
八、常见问题Q&A
Q1:为什么打包后曝光设置无效?
答: 可能你误用了 #if UNITY_EDITOR 包裹了整段逻辑。应只用于识别逻辑判断,不影响运行时的代码执行。
Q2:URP下曝光值始终不变?
答: 请检查Exposure组件是否启用,并确保Mode为Fixed,否则不会响应fixedExposure.value设置。
Q3:支持Timeline绑定吗?
答: 可将 exposure 变量声明为 public,直接在Timeline中作为可动画属性进行关键帧绑定。
小结
通过本文的组件实现,我们可以在不同渲染管线下统一控制天空盒的曝光度,便于搭建日夜交替、天气系统、剧情过渡等视觉表现。