【从UnityURP开始探索游戏渲染】专栏-直达

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 色彩空间配合使用时效果最佳,能够保持更广色域的色彩关系


【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,)

【URP】Unity[后处理]颜色曲线ColorCurves的更多相关文章

  1. 【Unity】贝塞尔曲线关于点、长度、切线计算在 Unity中的C#实现

    原文:[Unity]贝塞尔曲线关于点.长度.切线计算在 Unity中的C#实现 写在前面 最近给项目做了个路径编辑,基本思路是满足几个基本需求: [额外说明]其实本篇和这个没关系,可以跳过" ...

  2. Unity 后处理堆

    Unity安装后处理的过程:windows---PacageManager---Post Processing Post Processing后处理堆需要知道要修改那个相机渲染的内容,先定位到相机,再 ...

  3. Unity Shader-后处理:简单的颜色调整(亮度,饱和度,对比度)

    好久没坚持写blog了,是时候开始撸一波新博文了!学习Unity有一段时间了,关于Shader的书也看了几本<Unity Shader入门精要>,<Unity 3D ShaderLa ...

  4. Unity3D学习笔记11——后处理

    目录 1. 概述 2. 详论 2.1. 实现 2.2. 解析 1. 概述 一般来说,图形渲染引擎都会把帧缓冲(Framebuffer)技术封装成两个接口,其中之一就是后处理(Post-process) ...

  5. Unity的Write Defaults->从一个例子谈起

    Write Defaults是什么? 在Unity的Animator中点击任何一个手动创建的State,我们就会在Inspector面板中看到下图的WriteDefaults选项 (图1,Animat ...

  6. Unity3D使用小技巧

    原地址:http://unity3d.9tech.cn/news/2014/0411/40178.html 1.Crtl+f摄像机自动适配场景. 2.可以用一个立方体作为底盘. 3.人物角色可以直接引 ...

  7. Ng机器学习笔记-1-一元线性回归

    一:回归模型介绍 从理论上讲,回归模型即用已知的数据变量来预测另外一个数据变量,已知的数据属性称为输入或者已有特征,想要预测的数据称为输出或者目标变量. 下图是一个例子: 图中是某地区的面积大小与房价 ...

  8. GDI+编程说明及小结

    原文地址:http://blog.csdn.net/byxdaz/article/details/5972759 GDI+(Graphics Device Interface Plus图形设备接口加) ...

  9. Gimp教程:制作彩色的网站横幅

    效果图: Step1.新建900x200的透明图层 Step2.点选画笔工具,在左下方的设置界面进行如下: 设置画笔,动态,颜色,勾选应用抖动,然后试着在图层上画一画,调节一下画笔大小,相信你能作出如 ...

  10. 好看又能打的CRM系统大比拼:Salesforce, SugarCRM, Odoo等

    介绍 今天的CRM市场提供了大量的解决方案和软件替代品.有些适合大型企业(通常需要内部托管),而其他企业则更多地应用于SME的需求(通常使用云托管解决方案). 在CRM解决方案方面,提供商必须调整其产 ...

随机推荐

  1. 用 LangGraph + MCP Server 打造 SpreadJS 智能助手:让 AI 真正懂你的表格需求

    前言 差不多今年,"MCP""Agent"一直都是AI领域的热点, 尤其是manus的出现, 显得Agent好像无所不能, 极大的展现了AI的思考和执行决策的能 ...

  2. Linux(入门)---001.desktop文件教程

    目录简介desktop文件基本模板Categories 参数示例简介软件程序添加"快捷方式" Desktop Entry文件是Linux桌面系统中用于描述程序启动配置信息的文件,它 ...

  3. PON测试,“信”助力 | 信而泰测试解决方案浅析

    PON介绍 一.什么是PON网络 PON是"Passive Optical Network"的缩写,是一种基于光纤的网络技术.PON网络通过单向的光信号传输来实现数据.语音和视频等 ...

  4. 磁盘分区之LVM

    磁盘分区之 lvm 1. 创建物理卷 pvcreate /dev/sdb 2. 创建卷组 vgcreate data-vg /dev/sdb 3. 创建逻辑卷 lvcreate -l 100%FREE ...

  5. SpringBoot @Async 异步处理:从使用到原理与最佳实践

    引言 在现代应用程序开发中,异步处理是提高系统性能和响应能力的关键技术.Spring Framework 通过 @Async 注解为开发者提供了简便的异步方法执行能力,而 Spring Boot 在此 ...

  6. 大华海康等摄像头、录像机通过GB28181注册LiveGBS国标流媒体实现网页直播的注册流程解析

    GB28181注册区分需要认证和无需认证 LiveGBS国标流媒体服务基础配置页面默认接入密码是:12345678 .如果不需要接入认证的话可以把接入密码填空. 注册流程 当密码不为空时即需要接入认证 ...

  7. LiveNVR - Onvif/RTSP接入各家摄像头直播与云台控制

    LiveNVR Onvif/RTSP流媒体服务,支持RTSP稳定拉流接入,支持Onvif协议接入,支持RTMP/HLS/HTTP-FLV分发,将传统安防监控设备互联化,无插件直播等. 什么是Onvif ...

  8. .net CPU和内存爆高的分析与处理01

    一.问题现象 从截图现象看,应用程序CPU和内存都上去了.并且还是导致程序崩溃了.这时我想到了在老师(一线码农)那里学到的分析办法,先抓取一个Dump.然后仔细分析. 二.分析Dump 通过Addre ...

  9. XSS 攻击与防御

    一.什么是 XSS 攻击? XSS(Cross Site Scripting)跨站脚本攻击:是指攻击者在网页中注入恶意脚本代码(通常是 JavaScript),当用户浏览该网页时,脚本会在用户的浏览器 ...

  10. 源码调试-带你了解下车牌识别的深度学习模型-LPRNet

    ​ 视频演示 源码调试-带你了解下车牌识别的深度学习模型-LPRNet 大家好,这里是Coding茶水间.本期我们来调试运行一个经典的深度学习网络--LPRNet,它专门用于车牌识别任务. LPRNe ...