寫在前面
在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中作為可動畫屬性進行關鍵幀綁定。
小結
通過本文的組件實現,我們可以在不同渲染管線下統一控制天空盒的曝光度,便于搭建日夜交替、天氣系統、劇情過渡等視覺表現。