Unity Shader 系列(五):Unity 颜色管理与 URP 后处理 — 赛博朋克风格特效
Linear vs Gamma:最容易踩的颜色陷阱
许多 Unity 项目的颜色看起来”不对”——材质太亮、阴影太浅、HDR 泛光颜色偏差——根本原因往往是对 Linear/Gamma 工作流的误解。
核心问题:人眼对亮度的感知是非线性的(gamma 约 2.2)。显示器为适配人眼也用 gamma 编码存储颜色。但物理光照计算必须在线性空间进行,否则结果是错误的。
Unity 的两种工作流:
| 设置 | 位置 | 推荐场景 |
|---|---|---|
Linear |
Project Settings → Player → Color Space | 所有写实渲染项目(URP 默认) |
Gamma |
同上 | 旧项目兼容,2D 像素风格游戏 |
在 Linear 工作流下,Unity 自动处理:
- 纹理从 sRGB(gamma 编码)读取时自动线性化(如果纹理标记为
sRGB) - 最终渲染结果自动应用 gamma 编码后输出到显示器
- Shader 中的颜色属性(
Color类型)自动从 sRGB 转换为线性传入
不会自动处理的情况(需要手动注意):
- 法线贴图、Mask 贴图:必须在 Import Settings 中取消
sRGB勾选,否则 Unity 会错误地对非颜色数据进行线性化 - 自定义 RenderTexture:需要手动设置
RenderTextureFormat的 sRGB 标志 - 在 Shader 中手动做颜色空间转换
Shader 中的颜色空间转换
1 | |
URP 后处理架构
URP 的后处理系统基于 Volume 框架:
- 在场景中创建
Global Volume对象 - 添加
Bloom、Color Grading、Tonemapping等 Override - URP 在最终 Blit 阶段自动应用这些效果
内置效果链(执行顺序):
1 | |
自定义后处理:Custom Renderer Feature
URP 允许通过 ScriptableRendererFeature 插入自定义 Pass:
1 | |
完整示例:赛博朋克风格后处理 Shader
色相偏移 + 扫描线 + 故障噪声(Glitch)的完整 URP Custom Post Process Shader:
1 | |
HDR 与 Bloom 的正确配合
在 Unity Linear 工作流中,_EmissionColor 超过 1 就进入 HDR 范围,Bloom 效果只提取亮度超过阈值的像素:
1 | |
URP Color Grading LUT 工作原理
URP 的 Color Grading 使用 3D LUT(Look-Up Table)实现:
- 将渲染好的 HDR 画面通过 Tonemapping 映射到 [0,1]
- 用映射后的 RGB 值作为 3D 坐标,查找 LUT 纹理中的目标颜色
- 输出最终 sRGB 颜色
自定义 LUT 工作流:
- 从 Unity 导出基础 LUT 图片(
Post Processing → Export LUT) - 在 Photoshop/DaVinci Resolve 中调色
- 保存为
.png并导入 Unity(取消 sRGB,格式选R8G8B8) - 在
Color LookupVolume Override 中指定
ShaderGraph 实现色彩调整
ShaderGraph 在 URP 中也支持后处理(通过 Fullscreen Shader Graph):
- 创建
Fullscreen Shader Graph(6.0+ 支持) - 节点连接:
URP Sample Buffer节点(采样屏幕颜色)Hue节点(调整色相)Saturation节点(调整饱和度)Contrast节点(调整对比度)
- 在
Custom Post Process VolumeC# 脚本中引用材质
性能考量
| 效果 | 移动端开销 | 建议 |
|---|---|---|
| 色差(3 次采样) | 低-中 | 强度限制在 0.3 以内 |
| 扫描线(纯数学) | 极低 | 可在移动端保留 |
| Glitch(随机 + 采样) | 中 | 移动端可降低触发频率 |
| 色相/饱和度调整 | 低 | HSV 转换约 8 条指令 |
| 暗角(smoothstep) | 极低 | 可在所有平台使用 |
移动端优化:
- 色差的 3 次采样中,绿通道直接用屏幕中心 UV,只有红蓝偏移,减少 1 次采样
- 扫描线用
step代替sin(更快,但有锯齿感) - Glitch 效果默认关闭(
_GlitchStrength = 0),用#pragma shader_feature编译变体
常见踩坑
**Gamma 空间下的颜色看起来”过曝”**:如果项目用 Gamma 色彩空间,美术在 Linear 显示器上调的颜色在 Gamma 空间会显得更亮。团队要统一在 Linear 空间工作。
法线贴图/Mask 贴图被错误地 sRGB 处理:在 Texture Import Settings 中,法线贴图要选
Normal map类型(自动关闭 sRGB),自定义数据纹理要手动取消sRGB Color勾选。混淆后法线会偏蓝,AO/Roughness 贴图值会非线性偏移。后处理 Shader 中不要手动做 Gamma 编码:URP 的后处理 Pass 在 Linear 空间运行,最终由 URP 的输出阶段自动处理 Gamma。如果手动
pow(color, 1.0/2.2),颜色会被双重 Gamma 编码变得过暗。HDR 颜色属性
[HDR]标签:在 Properties 中不加[HDR]的颜色属性只能设置 [0,1] 范围,Inspector 中的颜色选择器不会显示强度滑块,无法设置超过 1 的 HDR 值。_Time.y在暂停时不会停止:Unity 的_Time.y是不受Time.timeScale = 0影响的(实际上受影响,但 UI 后处理材质可能使用_UnscaledTime)。如果需要响应游戏暂停,在 C# 中传入自定义 float 代替直接使用_Time.y。
下一篇文章将转向 3D SDF 在 Unity 中的实际应用——体积雾、软粒子,以及如何用 URP Custom Render Feature 实现基于 SDF 的局部雾效。