news 2026/4/18 9:43:40

【URP】Unity[后处理]颜色曲线ColorCurves

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【URP】Unity[后处理]颜色曲线ColorCurves

ColorCurves 是 Unity 通用渲染管线(URP)中的一种高级颜色分级工具,它允许通过曲线精细调整图像的色相、饱和度和亮度。这种工具最初在专业影视后期软件(如 Fusion)中成熟应用,后被引入游戏引擎用于实时渲染的色彩控制。

ColorCurves 提供了8条独立曲线,包括:

Master(整体亮度)

‌功能‌:整体调整图像的亮度和对比度。

‌实现‌:通过调整曲线形状控制全局亮度,曲线向上提升亮度,向下降低亮度

Red/Green/Blue(单通道调整,三条曲线)

功能‌:分别单独调整红、绿、蓝通道的亮度和色彩平衡。

‌实现‌:针对分量进行独立调节,影响图像中红、绿蓝区域的显色强度

HueVsHue(色调替换 色相-色相曲线)

‌功能‌:基于色相替换颜色(如将红色替换为蓝色)。

‌实现‌:通过映射原始色相到目标色相,实现颜色转换

HueVsSat(色调饱和度调整 色相-饱和度曲线)

功能‌:根据色相调整特定颜色的饱和度。

‌实现‌:选择特定色相范围后,增加或降低其饱和度

SatVsSat(饱和度对比 饱和度-饱和度曲线)

‌功能‌:基于当前饱和度进一步调整饱和度。

‌实现‌:对低饱和度区域增强或高饱和度区域抑制,实现非线性调整

LumVsSat(亮度饱和度关系 亮度-饱和度曲线)

功能‌:根据亮度调整饱和度(如增强暗部饱和度)。

‌实现‌:在低亮度区域提升饱和度以增强视觉对比,或在高亮度区域降低饱和度避免过曝

发展历史

颜色曲线技术起源于电影工业的后期调色流程,早期在 DaVinci Resolve 等专业调色软件中实现。Unity 在 2017 年引入 Post-processing Stack v1 时首次包含了基础曲线调整,2019 年 URP 正式版将其整合为 ColorCurves 模块,并增加了针对游戏优化的 ACES 色彩空间支持。

实现原理

ColorCurves 在渲染管线的后处理阶段工作,位于色调映射之前。它通过以下步骤实现:

将输入图像分解为 HSL 分量

对每个分量应用预定义的曲线变换

重新组合分量并输出到下一处理阶段

曲线映射原理

ColorCurves通过8条独立曲线对图像进行分通道处理,每条曲线采用256个控制点的查找表(LUT)实现非线性映射。例如Master曲线采用x轴(输入亮度)到y轴(输出亮度)的映射关系,通过贝塞尔插值算法实现平滑过渡。

贝塞尔曲线

‌通用公式

对于n阶贝塞尔曲线,其参数方程为:

$B(t)=\sum_{i=0}{n}\binom{n}{i}(1−t)t^iP_i,t\in[0,1]$

其中:

$P_i$为控制点,共n+1个;

$\binom{n}{i}$为组合数;

t为参数,控制曲线上的位置‌。

‌常见类型‌

‌线性 1阶‌:两点间直线,公式为

$B(t)=(1−t)P_0+tP_1$

‌二次 2阶‌:3个控制点,公式为

$B(t)=(1−t)2P_0+2t(1−t)P_1+t2P_2$

‌三次 3阶‌:4个控制点,公式为

$B(t)=(1−t)3P_0+3(1−t)2tP_1+3(1−t)t2P2+t3P_3$

三次贝塞尔曲线因平衡计算复杂性和灵活性,成为图形学中最常用的类型‌

实现方法

‌递归计算‌:通过德卡斯特里奥算法(De Casteljau's algorithm)逐步插值中间点‌;

‌矩阵表示‌:将三次贝塞尔曲线表示为控制点与基函数的矩阵乘法‌;

‌代码示例‌(Unity/C#):(注:实际应用中需处理浮点精度和性能优化)‌

csharp

public Vector3 CalculateBezierPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {

float u = 1 - t;

return u*u*u * p0 + 3*u*u*t * p1 + 3*u*t*t * p2 + t*t*t * p3;

}

通道处理流程

‌RGB通道分离‌:先将图像分解为R/G/B三个通道:

channelR = (R,0,0)

channelG = (0,G,0)

channelB = (0,0,0)

HLSL中常用亮度公式Luminance=0.2126×R+0.7152×G+0.0722×B

该公式基于CIE 1931色彩空间的人眼感知权重

RGB_Separate.hlsl

hlsl

Texture2D InputTexture : register(t0);

SamplerState LinearSampler : register(s0);

struct PS_Input {

float4 Position : SV_POSITION;

float2 UV : TEXCOORD;

};

// 红色通道分离

float4 PS_RedChannel(PS_Input input) : SV_TARGET {

float3 color = InputTexture.Sample(LinearSampler, input.UV).rgb;

return float4(color.r, 0, 0, 1); // 仅保留R分量

}

// 绿色通道分离

float4 PS_GreenChannel(PS_Input input) : SV_TARGET {

float3 color = InputTexture.Sample(LinearSampler, input.UV).rgb;

return float4(0, color.g, 0, 1); // 仅保留G分量

}

// 蓝色通道分离

float4 PS_BlueChannel(PS_Input input) : SV_TARGET {

float3 color = InputTexture.Sample(LinearSampler, input.UV).rgb;

return float4(0, 0, color.b, 1); // 仅保留B分量

}

// 亮度计算

float4 PS_Luminance(PS_Input input) : SV_TARGET {

float3 color = InputTexture.Sample(LinearSampler, input.UV).rgb;

float lum = dot(color, float3(0.2126, 0.7152, 0.0722));

return float4(lum.xxx, 1); // 灰度输出

}

‌曲线应用‌:

主通道:Master曲线同时影响所有通道

作为全局亮度调整曲线,直接对RGB三通道进行统一映射。公式为:Output=f_master(Input)

其中Input是原始亮度值(0-1),f_master是用户定义的曲线函数

分通道:Red/Green/Blue曲线分别处理对应通道

HueVsHue曲线

实现色相替换效果,通过角度偏移改变特定色相。HSV空间中的公式:H_out=H_in+f_hue(H_in)∗360°

f_hue是定义在0-1范围的曲线,输出值作为角度偏移量。

HueVsSat曲线

控制不同色相区域的饱和度增强/减弱: S_out=S_in∗(1+f_sat(H_in))

f_sat曲线输出-1到1的值,负值降低饱和度,正值增加。

SatVsSat曲线

非线性调整饱和度分布:S_out=f_satmap(S_in)

直接重映射饱和度值,常用于创建哑光效果。

LumVsSat曲线

基于亮度控制饱和度:S_out=S_in∗(1+f_lum(L_in))

L_in是HSL亮度值,f_lum曲线控制不同亮度区域的饱和度变化

ColorCurves.hlsl

使用纹理采样实现曲线查找,提升GPU执行效率

RgbToHsv/HsvToRgb需自行实现标准色彩空间转换

曲线参数通过纹理传入,支持任意形状的调整曲线

最终效果是各曲线调整的叠加组合

在C#中可通过Shader.SetGlobalTexture传递曲线纹理,或在CPU端实现类似算法处理图像数据。实际应用时通常配合UI控件让用户交互式调整曲线形状。

// 输入参数

Texture2D InputTexture;

SamplerState LinearSampler;

float4 HueVsHueCurve; // 曲线采样纹理

float4 HueVsSatCurve;

float4 SatVsSatCurve;

float4 LumVsSatCurve;

float3 ApplyColorCurves(float3 rgb)

{

// 转换到HSV空间

float3 hsv = RgbToHsv(rgb);

float hue = hsv.x;

float sat = hsv.y;

float lum = GetLuminance(rgb);

// HueVsHue处理

float hueOffset = SampleCurve(HueVsHueCurve, hue);

hsv.x = frac(hue + hueOffset);

// HueVsSat处理

float satScale = SampleCurve(HueVsSatCurve, hue) * 2.0 - 1.0;

hsv.y = sat * (1.0 + satScale);

// SatVsSat处理

hsv.y = SampleCurve(SatVsSatCurve, sat);

// LumVsSat处理

float lumSatScale = SampleCurve(LumVsSatCurve, lum) * 2.0 - 1.0;

hsv.y = sat * (1.0 + lumSatScale);

// 返回RGB空间

return HsvToRgb(hsv);

}

// 辅助函数

float SampleCurve(float4 curve, float x)

{

return curve.SampleLevel(LinearSampler, float2(x, 0), 0).r;

}

‌色相转换‌:将RGB转换为HSV色彩空间处理HueVsHue等曲线

HSV(Hue, Saturation, Value)是一种基于人类视觉感知的直观颜色模型,由色相(H)、饱和度(S)和明度(V)三个分量组成‌

基本概念

‌色相H‌:表示颜色类型,取值范围0°-360°(如红色0°、绿色120°、蓝色240°),通过色轮角度定位颜色‌。

‌饱和度S‌:表示颜色纯度,0%为灰色,100%为纯色,数值越高颜色越鲜艳‌。

‌明度V‌:控制颜色亮度,0%为黑色,100%为最亮(如白色需S=0%、V=100%)‌

模型特点

‌六角锥体结构‌:从RGB立方体演化而来,色调H沿圆周分布,饱和度S和明度V分别表示径向和轴向距离‌。

‌符合直觉‌:比RGB更接近传统绘画调色习惯,适合直观调整颜色属性(如Photoshop调色板)‌。

‌分量独立‌:亮度V与颜色无关,仅影响光照强度;色调H和饱和度S互不干扰‌

RGB转HSV

HSV转RGB

ColorSpace.hlsl

// RGB转HSV

float3 RGBtoHSV(float3 rgb) {

float cmax = max(rgb.r, max(rgb.g, rgb.b));

float cmin = min(rgb.r, min(rgb.g, rgb.b));

float delta = cmax - cmin;

float h = 0;

if (delta != 0) {

if (cmax == rgb.r)

h = 60 * fmod(((rgb.g - rgb.b)/delta + 6), 6);

else if (cmax == rgb.g)

h = 60 * ((rgb.b - rgb.r)/delta + 2);

else

h = 60 * ((rgb.r - rgb.g)/delta + 4);

}

float s = (cmax == 0) ? 0 : delta / cmax;

return float3(h, s, cmax);

}

// HSV转RGB

float3 HSVtoRGB(float3 hsv) {

float c = hsv.z * hsv.y;

float x = c * (1 - abs(fmod(hsv.x / 60, 2) - 1));

float m = hsv.z - c;

float3 rgb;

if (hsv.x < 60) rgb = float3(c, x, 0);

else if (hsv.x < 120) rgb = float3(x, c, 0);

else if (hsv.x < 180) rgb = float3(0, c, x);

else if (hsv.x < 240) rgb = float3(0, x, c);

else if (hsv.x < 300) rgb = float3(x, 0, c);

else rgb = float3(c, 0, x);

return rgb + m;

}

示例:实现冷色调增强

// 在Volume组件中添加ColorCurves重载

var curves = volumeProfile.Add<ColorCurves>();

curves.active = true;

// 调整蓝色通道曲线

curves.blue.Override(new AnimationCurve(

new Keyframe(0, 0),

new Keyframe(0.5f, 0.7f),

new Keyframe(1, 1)

));

// 降低暖色饱和度

curves.hueVsSat.Override(new AnimationCurve(

new Keyframe(0.1f, 0.8f),// 红色范围

new Keyframe(0.6f, 1.2f)// 蓝色范围

));

该示例通过提升中间调蓝色和抑制红色饱和度,实现电影级冷色调效果。

伽马校正处理

URP会在曲线处理前后自动执行伽马/线性空间转换,确保颜色混合符合物理正确性。具体流程:

输入图像从sRGB转为线性空间

应用所有曲线调整

结果转换回sRGB空间输出

性能优化

采用计算着色器并行处理LUT生成,每条曲线仅需1次纹理采样,8条曲线共产生约0.3ms的性能开销(1080p分辨率)。建议避免每帧动态修改曲线控制点,改为预烘焙多套曲线配置。

完整示例

ColorCurvesExample.cs

using UnityEngine;

using UnityEngine.Rendering;

using UnityEngine.Rendering.Universal;

[System.Serializable]

public class ColorCurvesSettings

{

public AnimationCurve masterCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve redCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve greenCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve blueCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve hueVsHueCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve hueVsSatCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve satVsSatCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

public AnimationCurve lumVsSatCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));

}

public class CustomColorCurvesRenderPass : ScriptableRenderPass

{

private Material m_Material;

private ColorCurvesSettings m_Settings;

public CustomColorCurvesRenderPass(Material material, ColorCurvesSettings settings)

{

m_Material = material;

m_Settings = settings;

}

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)

{

if (m_Material == null) return;

CommandBuffer cmd = CommandBufferPool.Get("Color Curves");

// 设置曲线参数

m_Material.SetTexture("_MasterCurve", CreateCurveTexture(m_Settings.masterCurve));

m_Material.SetTexture("_RedCurve", CreateCurveTexture(m_Settings.redCurve));

m_Material.SetTexture("_GreenCurve", CreateCurveTexture(m_Settings.greenCurve));

m_Material.SetTexture("_BlueCurve", CreateCurveTexture(m_Settings.blueCurve));

m_Material.SetTexture("_HueVsHueCurve", CreateCurveTexture(m_Settings.hueVsHueCurve));

m_Material.SetTexture("_HueVsSatCurve", CreateCurveTexture(m_Settings.hueVsSatCurve));

m_Material.SetTexture("_SatVsSatCurve", CreateCurveTexture(m_Settings.satVsSatCurve));

m_Material.SetTexture("_LumVsSatCurve", CreateCurveTexture(m_Settings.lumVsSatCurve));

// 执行后处理

Blit(cmd, renderingData.cameraData.renderer.cameraColorTarget,

renderingData.cameraData.renderer.cameraColorTarget, m_Material);

context.ExecuteCommandBuffer(cmd);

CommandBufferPool.Release(cmd);

}

private Texture2D CreateCurveTexture(AnimationCurve curve)

{

Texture2D texture = new Texture2D(256, 1, TextureFormat.RFloat, false);

for (int i = 0; i < 256; i++)

{

float value = curve.Evaluate(i / 255f);

texture.SetPixel(i, 0, new Color(value, 0, 0, 0));

}

texture.Apply();

return texture;

}

}

使用流程

在 Unity 中创建 Volume 对象并添加 Color Curves 效果

调整各条曲线参数

通过预览窗口实时查看效果

参数详解与用例

Master 曲线

‌作用‌:全局亮度调整

‌用例‌:修正整体曝光不足或过曝的场景

RGB 曲线(Red/Green/Blue)

‌作用‌:单独调整各颜色通道

‌用例‌:修正色偏或创造风格化效果(如赛博朋克的蓝色调)

HueVsHue

‌作用‌:基于输入色调替换输出色调

‌用例‌:将绿色植被改为秋季黄色

HueVsSat

‌作用‌:调整特定色调的饱和度

‌用例‌:增强天空蓝色饱和度而不影响其他颜色

SatVsSat

‌作用‌:调整饱和度对比

‌用例‌:使高饱和区域更鲜艳,低饱和区域更灰

LumVsSat

‌作用‌:基于亮度调整饱和度

‌用例‌:使暗部区域降低饱和度(电影感效果)

实际应用技巧

‌电影感调色‌

使用 LumVsSat 降低暗部饱和度,HueVsHue 微调肤色

‌季节变换‌

通过 HueVsHue 将绿色变为黄色/红色模拟秋季

‌风格化效果‌

夸张的 S 形 RGB 曲线创造高对比度画面

‌色彩匹配‌

Match 功能原理,使用曲线匹配不同镜头的色彩

ColorCurves 与 Unity 的 ACES 色彩空间配合使用时效果最佳,能够保持更广色域的色彩关系

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:14:42

微软 Foundry Local - 本地 AI 推理解决方案

软在其 2025 Build 大会上发布了 Foundry Local&#xff0c;能够在本地设备上执行 AI 推理&#xff0c;意味着可以利用本地的 AI 算力&#xff0c;如&#xff1a;CPU/GPU/NPU&#xff1b;也让用户在隐私方面得到了充足的保障&#xff0c;还能有改善成本效益&#xff01;Foundry…

作者头像 李华
网站建设 2026/4/17 9:49:03

Git能上传多大的文件

Git 本身对文件大小没有强制上限&#xff0c;但核心限制来自两个层面&#xff1a;Git 的设计初衷和远程仓库的规则&#xff08;比如 GitHub、GitLab、Gitee 等平台的限制&#xff09;&#xff0c;结合你当前“上传包含嵌套文件夹/子模块”的场景&#xff0c;具体说明如下&#…

作者头像 李华
网站建设 2026/4/7 8:12:25

什么是社会工程学?防范社会工程学攻击的最有效方法是什么?

黑客技术就像魔术&#xff0c;处处充满了欺骗。 不要沉迷于网络技术&#xff0c;人才是突破信息系统的关键。 只要敢做就能赢。 在电影《我是谁&#xff1a;没有绝对安全的系统》中&#xff0c;主角本杰明充分利用自己高超的黑客技术&#xff0c;非法入侵国际安全系统&#xff…

作者头像 李华