【從UnityURP開始探索遊戲渲染】專欄-直達
ChannelMixer是Unity URP後處理系統中用於顏色通道混合的核心效果組件,主要用於調整RGB通道的混合比例以實現特定的色彩分級效果。其發展歷史可追溯至影視行業的傳統調色技術,後被整合到Unity的Post Processing Stack中,並隨着URP的演進成為Volume框架下的標準化模塊
核心功能與參數
通道混合原理
通過修改輸入顏色通道(Red/Green/Blue)對輸出通道的貢獻權重,實現如單色保留、色調偏移等效果。例如增加綠色通道對紅色輸出的影響會使綠色區域偏紅。
ChannelMixer在Unity URP後處理中的底層原理基於顏色通道的線性代數變換,通過對RGB通道的權重矩陣運算實現色彩重構.
輸出通道 = (R × R權重) + (G × G權重) + (B × B權重) + 常數偏移
該計算在片元着色器中逐像素執行,通過矩陣乘法實現顏色空間轉換.
數學原理分解
-
通道變換矩陣
- 每個輸出通道由3×4變換矩陣控制(包含常數項),例如紅色輸出通道計算為:
- $R_{out}=R_{in}\times M_{00}+G_{in}\times M_{01}+B_{in}\times M_{02}+M_{03}$
- 其中M_03為常數偏移量。
-
亮度保持機制
- 當啓用Preserve Luminosity時,系統會自動歸一化權重係數,確保滿足:
- $M_{00}+M_{01}+M_{02}=1.0$
- 防止畫面過曝或欠曝
URP實現示例 關鍵實現解析
-
矩陣運算階段
片元着色器通過
dot(col.rgb, _RedOut.xyz)實現向量點乘,等效於矩陣乘法。例如設置_RedOut=(0.5,0.3,0.2)時,新紅色通道值為原RGB通道的50%+30%+20%混合。 -
動態參數傳遞
URP通過Volume組件將參數打包為Vector4(xyz為RGB權重,w為常數偏移),每幀更新至Shader。例如電影級調色常用配置:
csharp _RedOut = new Vector4(0.8f, 0.1f, 0.1f, 0);// 強化紅色主基調 _GreenOut = new Vector4(0f, 1.2f, -0.2f, 0);// 增強綠色並抑制藍色 -
後處理管線集成
RendererFeature在
BeforeRenderingPostProcessing事件點插入通道混合操作,通過雙次Blit避免直接修改源紋理。臨時渲染目標_TempChannelMixerTexture確保混合過程可逆. -
ChannelMixer.shader
Shader "PostProcessing/ChannelMixer" { Properties { _MainTex ("Texture", 2D) = "white" {} _RedOut ("Red Output", Vector) = (1,0,0,0) _GreenOut ("Green Output", Vector) = (0,1,0,0) _BlueOut ("Blue Output", Vector) = (0,0,1,0) } SubShader { HLSLPROGRAM #pragma only_renderers d3d11 #pragma exclude_renderers gles #pragma target 5.0 #pragma multi_compile_postprocess #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/PostProcessing.hlsl" TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); float4 _RedOut; float4 _GreenOut; float4 _BlueOut; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.vertex = TransformWorldToClipPos(v.vertex); o.uv = v.uv; return o; } float4 frag(v2f i) : SV_Target { float4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); float3 result; result.r = dot(col.rgb, _RedOut.xyz) + _RedOut.w; result.g = dot(col.rgb, _GreenOut.xyz) + _GreenOut.w; result.b = dot(col.rgb, _BlueOut.xyz) + _BlueOut.w; return float4(result, col.a); } ENDHLSL } } -
ChannelMixerRendererFeature.cs
using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class ChannelMixerRendererFeature : ScriptableRendererFeature { class CustomRenderPass : ScriptableRenderPass { Material _material; RenderTargetHandle _tempTexture; public CustomRenderPass(Material material) { _material = material; _tempTexture.Init("_TempChannelMixerTexture"); } public override void Execute(ScriptableRenderContext context, ref RenderingData data) { CommandBuffer cmd = CommandBufferPool.Get("Channel Mixer"); RenderTextureDescriptor desc = data.cameraData.cameraTargetDescriptor; cmd.GetTemporaryRT(_tempTexture.id, desc); Blit(cmd, source: "_CameraColorTexture", dest: _tempTexture.id, _material); Blit(cmd, source: _tempTexture.id, dest: "_CameraColorTexture"); cmd.ReleaseTemporaryRT(_tempTexture.id); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } } [System.Serializable] public class Settings { public Material material; } public Settings settings = new Settings(); CustomRenderPass _scriptablePass; public override void Create() { _scriptablePass = new CustomRenderPass(settings.material); _scriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData data) { renderer.EnqueuePass(_scriptablePass); } }
參數説明
- Output Channel:選擇要調整的目標通道(Red/Green/Blue)
- Red/Green/Blue Contribution:各輸入通道對當前輸出通道的影響權重(範圍-2到2)
- Preserve Luminosity:保持整體亮度不變,避免過度曝光。
實現流程示例
ChannelMixerExample.cs
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class ChannelMixerExample : VolumeComponent, IPostProcessComponent {
public Vector3Parameter redOut = new(new Vector3(1, 0, 0));
public Vector3Parameter greenOut = new(new Vector3(0, 1, 0));
public Vector3Parameter blueOut = new(new Vector3(0, 0, 1));
public bool IsActive() => true;
public bool IsTileCompatible() => false;
}
ChannelMixerRenderPass.cs
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class ChannelMixerRenderPass : ScriptableRenderPass {
private Material _material;
private ChannelMixerExample _volume;
public override void Execute(ScriptableRenderContext context, ref RenderingData data) {
_volume = VolumeManager.instance.stack.GetComponent<ChannelMixerExample>();
if (_volume == null) return;
var cmd = CommandBufferPool.Get("ChannelMixer");
_material.SetVector("_RedOut", _volume.redOut.value);
_material.SetVector("_GreenOut", _volume.greenOut.value);
_material.SetVector("_BlueOut", _volume.blueOut.value);
Blit(cmd, ref data, _material, 0);
context.ExecuteCommandBuffer(cmd);
}
}
實際應用案例
電影感調色
將藍色通道注入紅色輸出(如設置RedOut為(0.8, 0, 0.2)),可創造類似《黑客帝國》的青色陰影效果。
風格化渲染
通過反轉綠色通道貢獻(GreenOut設為(-0.5, 1, 0)),實現賽博朋克風格的色彩偏移。
黑白濾鏡
統一各通道權重(如RedOut=(0.3,0.6,0.1))可生成高質量灰度圖像,比直接去飽和度更可控。
膠片模擬
- 設置
BlueOut=(0,0,0.9,0.1)使藍色通道輕微壓縮,模擬柯達膠片特性
色盲輔助
- 將紅色通道注入綠色輸出(
GreenOut=(0.5,0.5,0,0))提升紅綠色盲辨識度
風格化渲染
- 負值權重創造互補色效果,如
RedOut=(1, -0.2, 0, 0)產生賽博朋克色調
操作步驟
- 在Volume中添加Channel Mixer效果
- 調整目標通道的RGB權重三角滑塊
- 啓用Preserve Luminosity避免過曝
該技術現已成為URP標準管線的一部分,通過Volume系統實現非破壞性調整,比傳統Shader方案更易集成到美術工作流中
【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)