Unity

第 11 章:URP 光照与渲染管线

第 11 章:URP 光照与渲染管线

前端类比:如果把游戏画面比作一个网页,那么渲染管线(Render Pipeline)就是浏览器的渲染引擎,光照是 CSS 的 filterbox-shadow,后处理效果是 Instagram 滤镜,而 Shader 就是 WebGL Shader——你可能写过 mix-blend-modebackdrop-filter,但 Unity 的渲染系统远比 CSS 强大和复杂。


本章目标

完成本章后,你将能够:

  1. 理解 URP(Universal Render Pipeline)的架构和配置
  2. 配置 URP Pipeline Asset 的各项参数
  3. 掌握四种光源类型及其适用场景
  4. 区分实时光照与烘焙光照,合理选择
  5. 理解 Lightmap 光照贴图的烘焙流程
  6. 使用 Reflection Probe 和 Light Probe 优化动态物体光照
  7. 正确配置阴影系统(分辨率、距离、级联)
  8. 使用 Post-Processing Volume 添加视觉效果
  9. 入门 Shader Graph(创建简单的自定义 Shader)
  10. 理解 PBR 材质系统(Albedo、Normal Map、Metallic、Emission)
  11. 配置 Camera Stacking(相机堆叠)

预计学习时间

6 小时(理论 2 小时 + 实操 4 小时)


11.1 渲染管线概述

11.1.1 什么是渲染管线

渲染管线(Render Pipeline)决定了 Unity 如何将 3D 场景绘制到屏幕上——包括光照计算方式、阴影算法、后处理流程等。

💡 前端类比:渲染管线类似浏览器的渲染引擎选择。Chrome 用 Blink,Firefox 用 Gecko,Safari 用 WebKit——不同引擎的渲染策略和性能特征不同。Unity 的渲染管线选择同理。

11.1.2 Unity 的三种渲染管线

渲染管线全称定位适用平台
Built-inBuilt-in Render Pipeline旧版默认管线通用(遗留项目)
URPUniversal Render Pipeline性能优先的通用管线移动端 + PC + 主机
HDRPHigh Definition Render Pipeline画质优先的高端管线高端 PC + 主机
选择渲染管线的决策:

开发手游?
├── 是 → URP(本教程使用)
│         性能优秀,功能够用

└── 否 → 追求 3A 画质?
          ├── 是 → HDRP
          │         适合高端平台

          └── 否 → URP(大多数情况最佳选择)

🎯 最佳实践:对于手游开发,始终选择 URP。它在保证画面质量的同时,对移动端 GPU 做了大量优化。

11.1.3 URP vs Built-in 的主要区别

方面Built-inURP
Shader 语言Surface Shader / HLSLShader Graph / HLSL
前向渲染灯光数量按像素光源 (Per-Pixel) 限制Single Pass,高效多光源处理
后处理需要额外包 (Post Processing Stack)内置 Volume 系统
SRP Batcher不支持支持(大幅减少 Draw Call)
可编程性不可编程可编程(Render Features)
性能一般移动端优化更好

11.2 URP 项目设置

11.2.1 新项目直接使用 URP

创建新项目时,在 Unity Hub 中选择 3D (URP) 模板即可。

[截图:Unity Hub 新建项目时选择 3D (URP) 模板]

11.2.2 现有项目升级到 URP

如果你的项目是 Built-in 管线,需要以下步骤升级:

步骤 1:安装 URP 包

  1. 菜单 → WindowPackage Manager
  2. 搜索 Universal RP
  3. 点击 Install

步骤 2:创建 URP Pipeline Asset

  1. Project 窗口右键 → CreateRenderingURP Asset (with Universal Renderer)
  2. 这会创建两个文件:
    • URP-Pipeline.asset(Pipeline Asset)
    • URP-Pipeline_Renderer.asset(Renderer Data)

[截图:Project 窗口中新创建的 URP Pipeline Asset 和 Renderer Data]

步骤 3:应用 URP Pipeline

  1. 菜单 → EditProject SettingsGraphics
  2. Scriptable Render Pipeline Settings 设为刚创建的 URP-Pipeline.asset

[截图:Graphics Settings 中设置 Scriptable Render Pipeline Settings]

步骤 4:升级材质

  1. 菜单 → EditRenderingMaterialsConvert Built-in Materials to URP
  2. 这会把旧的 Standard Shader 转为 URP 的 Universal Lit Shader

⚠️ 注意:升级后旧的 Standard Shader 材质可能显示为粉色(着色器不兼容),需要转换或手动重新指定 Shader。

11.2.3 URP Pipeline Asset 配置详解

选中 URP Pipeline Asset,在 Inspector 中配置:

[截图:URP Pipeline Asset 的完整 Inspector 面板]

URP Pipeline Asset 关键设置:

┌────────────────────────────────────────────┐
│ ===== Rendering =====                       │
│                                            │
│ Renderer List:                             │
│   [0] URP-Pipeline_Renderer                │  ← 默认渲染器
│                                            │
│ Depth Texture: ☑                           │  ← 深度纹理(后处理需要)
│ Opaque Texture: ☑                          │  ← 不透明纹理(折射效果需要)
│ Opaque Downsampling: None                  │
│                                            │
│ Terrain Holes: ☑                           │  ← 地形孔洞支持
│                                            │
│ ===== Quality =====                         │
│                                            │
│ HDR: ☑                                     │  ← 高动态范围(Bloom 等需要)
│ Anti Aliasing (MSAA): 2x / 4x             │  ← 抗锯齿
│ Render Scale: 1.0                          │  ← 渲染分辨率缩放
│                                            │     手游可设 0.75 提升性能
│                                            │
│ ===== Lighting =====                        │
│                                            │
│ Main Light:                                │
│   Rendering Mode: Per Pixel               │
│   Cast Shadows: ☑                          │
│                                            │
│ Additional Lights:                         │
│   Rendering Mode: Per Pixel               │  ← 或 Per Vertex(更省)
│   Per Object Limit: 4                     │  ← 每个物体最多受几个额外光源影响
│   Cast Shadows: ☑                          │
│                                            │
│ ===== Shadows =====                         │
│                                            │
│ Max Distance: 50                           │  ← 阴影最远距离(米)
│ Cascade Count: 2                           │  ← 级联阴影层数(1-4)
│ Working Unit: Metric                       │
│ Depth Bias: 1                              │
│ Normal Bias: 1                             │
│                                            │
│ ===== Post-processing =====                │
│                                            │
│ Grading Mode: Low Dynamic Range            │  ← 或 HDR
│ LUT Size: 32                               │
│ Fast sRGB/Linear: ☑                        │
└────────────────────────────────────────────┘

手游推荐设置:

设置项低端机中端机高端机
MSAAOff2x4x
Render Scale0.650.851.0
Additional Lights ModePer VertexPer PixelPer Pixel
Per Object Limit248
Shadow Distance3050100
Shadow Cascades124
Shadow Resolution51210242048

🎯 最佳实践:创建多个 URP Pipeline Asset(Low、Medium、High),在运行时根据设备性能动态切换:

// 动态切换画质
QualitySettings.SetQualityLevel(qualityIndex);
// 对应的 URP Pipeline Asset 在 Quality Settings 中配置

11.3 光源类型

11.3.1 四种光源

四种光源类型示意:

1. Directional Light(方向光)——太阳
   ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
   平行光线,照亮整个场景
   位置无关,只有方向有影响

2. Point Light(点光源)——灯泡
         ╲ │ ╱
        ── ● ──
         ╱ │ ╲
   从一个点向所有方向发光
   有范围(Range)限制

3. Spot Light(聚光灯)——手电筒

          ╱ ╲
         ╱   ╲
        ╱─────╲
   圆锥形光线
   有范围 + 角度限制

4. Area Light(面光源)——窗户/灯箱(仅烘焙)
   ┌──────────┐
   │ ↓↓↓↓↓↓↓↓ │
   │ ↓↓↓↓↓↓↓↓ │
   └──────────┘
   从一个面发出柔和光线
   只支持烘焙光照

11.3.2 各光源属性

创建光源: Hierarchy → 右键 → Light → 选择光源类型

[截图:Directional Light 的 Inspector 面板,标注各属性]

属性DirectionalPointSpotArea
Color光线颜色光线颜色光线颜色光线颜色
Intensity强度强度强度强度
Range范围(米)范围(米)
Spot Angle锥角(度)
Shadow Type仅烘焙
实时支持支持支持不支持
烘焙支持支持支持支持
性能开销低(只有一个)无实时开销

11.3.3 光源模式

每个光源可以设置三种模式:

模式说明性能适用
Realtime实时计算光照会移动或变化的光源
Mixed混合——间接光烘焙,直接光实时不移动但需要实时阴影的光源
Baked完全烘焙——光照信息存储为纹理永远不变的光源(推荐大量使用)
光源模式对比:

Realtime(实时):
  优点:完全动态,所有变化都实时反映
  缺点:性能开销大,间接光照质量有限
  用于:太阳(需要昼夜循环)、可移动的灯

Mixed(混合):
  优点:间接光照质量高,直接光照可调节
  缺点:需要烘焙,烘焙后间接光不能改变
  用于:固定位置但需要实时阴影的灯

Baked(烘焙):
  优点:性能几乎零开销,光照质量高
  缺点:完全静态,不能影响动态物体
  用于:建筑内灯光、装饰灯、永久性光源

11.3.4 光源设置代码

using UnityEngine;

/// <summary>
/// 动态光源控制示例
/// 例如:昼夜循环中的太阳光变化
/// </summary>
public class DynamicLightController : MonoBehaviour
{
    [Header("太阳光引用")]
    [SerializeField] private Light directionalLight;

    [Header("昼夜颜色设置")]
    [SerializeField] private Color dawnColor = new Color(1f, 0.6f, 0.3f);    // 黎明——暖橙色
    [SerializeField] private Color noonColor = new Color(1f, 0.96f, 0.9f);   // 正午——白色偏暖
    [SerializeField] private Color duskColor = new Color(1f, 0.4f, 0.2f);    // 黄昏——深橙色
    [SerializeField] private Color nightColor = new Color(0.1f, 0.1f, 0.3f); // 夜晚——深蓝色

    [Header("太阳强度")]
    [SerializeField] private float noonIntensity = 1.5f;
    [SerializeField] private float nightIntensity = 0.05f;

    /// <summary>
    /// 根据游戏时间更新太阳光
    /// </summary>
    /// <param name="timeOfDay">一天中的时间 (0-24 小时)</param>
    public void UpdateSunLight(float timeOfDay)
    {
        // 计算太阳角度(0 点在正下方,12 点在正上方)
        float sunAngle = (timeOfDay / 24f) * 360f - 90f;
        directionalLight.transform.rotation = Quaternion.Euler(sunAngle, 170f, 0f);

        // 根据时间插值颜色
        Color sunColor;
        float intensity;

        if (timeOfDay < 6f) // 夜晚 → 黎明 (0-6)
        {
            float t = timeOfDay / 6f;
            sunColor = Color.Lerp(nightColor, dawnColor, t);
            intensity = Mathf.Lerp(nightIntensity, noonIntensity * 0.5f, t);
        }
        else if (timeOfDay < 12f) // 黎明 → 正午 (6-12)
        {
            float t = (timeOfDay - 6f) / 6f;
            sunColor = Color.Lerp(dawnColor, noonColor, t);
            intensity = Mathf.Lerp(noonIntensity * 0.5f, noonIntensity, t);
        }
        else if (timeOfDay < 18f) // 正午 → 黄昏 (12-18)
        {
            float t = (timeOfDay - 12f) / 6f;
            sunColor = Color.Lerp(noonColor, duskColor, t);
            intensity = Mathf.Lerp(noonIntensity, noonIntensity * 0.5f, t);
        }
        else // 黄昏 → 夜晚 (18-24)
        {
            float t = (timeOfDay - 18f) / 6f;
            sunColor = Color.Lerp(duskColor, nightColor, t);
            intensity = Mathf.Lerp(noonIntensity * 0.5f, nightIntensity, t);
        }

        directionalLight.color = sunColor;
        directionalLight.intensity = intensity;
    }
}

11.4 实时光照 vs 烘焙光照

11.4.1 为什么需要烘焙光照

实时计算间接光照(光线反弹、全局光照)非常昂贵,移动端几乎不可能实时计算。解决方案是**预先计算(烘焙)**这些光照信息,存储为纹理(Lightmap)。

实时 vs 烘焙光照对比:

实时光照:
  每一帧 GPU 都计算光照 → 性能开销大
  ┌─────────────┐
  │ 光源 → GPU  │──→ 直接照明 ✓
  │ 每帧计算    │──→ 间接照明 ✗(太贵)
  └─────────────┘

烘焙光照:
  离线预计算 → 存储为纹理 → 运行时几乎无开销
  ┌─────────────┐    ┌──────────────┐
  │ 离线计算    │──→ │ Lightmap 纹理│──→ 直接照明 ✓
  │(烘焙过程) │    │ (预计算好的)│──→ 间接照明 ✓
  └─────────────┘    └──────────────┘
  缺点:只能照亮静态物体,占存储空间

💡 前端类比:烘焙光照类似 SSG(Static Site Generation)——预先生成好内容(光照),运行时直接使用,性能极佳但不够动态。实时光照类似 SSR(Server-Side Rendering)——每次请求都计算,灵活但开销大。

11.4.2 设置静态物体

只有标记为 Static 的物体才能接收烘焙光照。

  1. 选中场景中的静态物体(地面、建筑、石头等)
  2. 在 Inspector 顶部勾选 Static → 选择 Contribute GI

[截图:Inspector 顶部的 Static 下拉菜单,标注 Contribute GI 选项]

Static 标记的类型:
┌──────────────────────────────────────┐
│ ☑ Contribute GI       ← 参与全局光照烘焙(最重要)
│ ☑ Occluder Static      ← 作为遮挡剔除的遮挡物
│ ☑ Occludee Static      ← 作为遮挡剔除的被遮挡物
│ ☑ Batching Static      ← 参与静态批处理(优化 Draw Call)
│ ☑ Navigation Static    ← 参与 NavMesh 导航烘焙
│ ☑ Reflection Probe Static ← 参与反射探针烘焙
└──────────────────────────────────────┘

11.4.3 烘焙光照贴图

  1. 菜单 → WindowRenderingLighting
  2. 在 Lighting 窗口中切换到 Baked Lightmaps 标签
  3. 配置烘焙参数

[截图:Lighting 窗口的完整界面]

Lightmap 烘焙设置(手游推荐):

┌──────────────────────────────────────┐
│ ===== Lightmapper =====              │
│                                      │
│ Lightmapper: Progressive GPU        │  ← 使用 GPU 加速烘焙(推荐)
│                                      │
│ ===== Lightmap Resolution =====      │
│                                      │
│ Lightmap Resolution: 20             │  ← 每单位像素数
│                                      │     手游用 10-20,PC 用 40+
│ Lightmap Padding: 2                  │
│ Max Lightmap Size: 1024             │  ← 单张 Lightmap 最大尺寸
│                                      │     手游用 1024,PC 用 2048
│ Lightmap Compression: Normal         │
│ Compress Lightmaps: ☑                │
│                                      │
│ ===== Indirect Lighting =====        │
│                                      │
│ Indirect Intensity: 1               │  ← 间接光强度
│ Indirect Resolution: 2              │
│ Environment Lighting: Skybox         │
│                                      │
│ ===== Bounces =====                  │
│                                      │
│ Max Bounces: 2                       │  ← 光线反弹次数
│                                      │     越多越真实但越慢
│                                      │     手游用 2,PC 用 3-4
└──────────────────────────────────────┘
  1. 点击 Generate Lighting 开始烘焙
  2. 烘焙完成后,会在场景同名文件夹下生成 Lightmap 纹理

[截图:烘焙完成后的场景效果对比——烘焙前(无间接光)vs 烘焙后(有间接光)]

⚠️ 注意:烘焙可能需要几分钟到几十分钟(取决于场景复杂度和参数)。开发阶段可以降低分辨率和反弹次数来加速。


11.5 反射探针(Reflection Probe)和光探针(Light Probe)

11.5.1 为什么需要探针

烘焙光照只影响静态物体。那动态物体(角色、NPC、可移动的道具)怎么办?

  • Light Probe:为动态物体提供间接光照信息
  • Reflection Probe:为物体提供环境反射信息
探针工作原理:

Light Probe(光探针):
  在空间中放置若干探测点,烘焙时记录每个点的光照环境
  运行时,动态物体根据位置在最近的探测点之间插值获取光照

  ●──●──●──●──●      ← 光探针网格
  │  │  │  │  │
  ●──●──●──●──●
  │  🧍 │  │  │      ← 动态角色根据位置在探针之间插值
  ●──●──●──●──●

Reflection Probe(反射探针):
  在指定位置捕获 360° 环境贴图(CubeMap)
  物体使用最近的反射探针获取反射信息

  ┌─────────────┐
  │   🏠        │
  │       [RP]  │      ← 反射探针在房间中心
  │         🪞  │      ← 金属/光滑物体会反射探针捕获的环境
  └─────────────┘

11.5.2 放置 Light Probe

  1. Hierarchy → 右键 → LightLight Probe Group
  2. 在 Scene 视图中选中 Light Probe Group
  3. 在 Inspector 中点击 Edit Light Probes 进入编辑模式
  4. 添加/删除/移动探针点

[截图:场景中的 Light Probe Group,显示黄色探针点和连线]

Light Probe 放置原则:

好的放置:                    不好的放置:
●     ●     ●               ●●●●●●●●●●●●
    ●     ●                  太多太密——浪费
●     ●     ●
在光照变化的地方              ●           ●
密度更高                     太少太稀——无法表达
                             光照变化
推荐:
- 门口、窗户附近密一些(光照变化大)
- 走廊、过渡区域密一些
- 开阔空地疏一些
- 角色不会到达的地方不放

11.5.3 放置 Reflection Probe

  1. Hierarchy → 右键 → LightReflection Probe
  2. 调整 Probe 的 Box Size 覆盖需要的区域
  3. 设置 Type(Baked 或 Realtime)

[截图:Reflection Probe 的 Inspector 面板和场景中的范围框]

Reflection Probe 设置:

┌──────────────────────────────────────┐
│ Type: Baked                          │  ← 烘焙(推荐)或 Realtime
│                                      │
│ Runtime Settings:                    │
│   Importance: 1                      │  ← 优先级(重叠区域取高优先级)
│   Box Size: (10, 5, 10)             │  ← 影响范围
│   Box Offset: (0, 0, 0)             │
│   Box Projection: ☑                  │  ← 室内环境推荐开启
│                                      │
│ Resolution: 128                      │  ← 反射贴图分辨率
│                                      │     手游用 64-128
│ HDR: ☑                               │
│ Shadow Distance: 0                   │  ← 反射中是否包含阴影
│                                      │
│ Time Slicing: All Faces At Once      │  ← 实时探针的更新策略
└──────────────────────────────────────┘

🎯 最佳实践

  • 室内每个房间放一个 Reflection Probe
  • 室外在关键区域(水面、金属建筑旁)放置
  • 手游使用 Baked 模式,避免 Realtime 的性能开销
  • 分辨率不要太高,128 对手游足够

11.6 阴影系统

11.6.1 阴影的重要性

阴影是让 3D 场景看起来”真实”最重要的因素之一——没有阴影,物体会像浮在空中一样不自然。

💡 前端类比:阴影在 3D 中的作用就像 CSS box-shadow 在 UI 设计中的作用——提供深度感和空间感。Material Design 整套设计语言就建立在 elevation(阴影)之上。

11.6.2 阴影配置

在 URP Pipeline Asset 中配置全局阴影:

Shadow Settings:

┌──────────────────────────────────────┐
│ ===== Shadows =====                   │
│                                      │
│ Main Light Shadow:                   │
│   Cast Shadows: ☑                    │
│   Shadow Resolution: 2048           │  ← 阴影贴图分辨率
│                                      │     手游推荐 1024-2048
│                                      │
│ Max Distance: 50                     │  ← 阴影渲染最大距离(米)
│                                      │     超过此距离的物体无阴影
│                                      │     手游推荐 30-50
│                                      │
│ Cascade Count: 2                     │  ← 级联阴影层数
│                                      │     越多越细腻,越耗性能
│                                      │     手游推荐 2
│                                      │
│ Split 1: 0.25                        │  ← 第一级占比
│                                      │
│ Depth Bias: 1                        │  ← 深度偏移(防止自阴影伪影)
│ Normal Bias: 1                       │  ← 法线偏移
│                                      │
│ Soft Shadows: ☑                      │  ← 软阴影(更柔和的边缘)
│                                      │     性能开销稍大
└──────────────────────────────────────┘

11.6.3 级联阴影(Shadow Cascades)

级联阴影原理:

不使用级联(1级):
  ┌──────────────────────────────────────┐
  │ ████ 近处也粗糙   远处也粗糙 ▓▓▓▓   │  ← 整个距离用同一张阴影贴图
  └──────────────────────────────────────┘
  相机                              最大距离
  效果:近处阴影锯齿严重

使用 4 级级联:
  ┌─────┬────────┬────────────┬──────────┐
  │█████│ ████   │  ▓▓▓▓      │  ░░░░    │
  │高精度│ 中精度 │  低精度    │  最低    │
  └─────┴────────┴────────────┴──────────┘
  相机   近   ←─→  中  ←─→  远  ←─→  最远
  效果:近处阴影清晰,远处允许降低质量

手游推荐 2 级:
  ┌──────────┬───────────────────────────┐
  │ ████████ │  ░░░░░░░░░░░░░░          │
  │ 近处高精度│  远处低精度               │
  └──────────┴───────────────────────────┘

11.6.4 物体的阴影设置

每个 Mesh Renderer 都有独立的阴影设置:

MeshRenderer → Lighting 部分:

Cast Shadows:
  Off       ← 不投射阴影
  On        ← 投射阴影(默认)
  Two Sided ← 双面投射(薄片状物体用)
  Shadows Only ← 只有阴影,物体不可见(用于阴影占位)

Receive Shadows: ☑  ← 是否接收其他物体的阴影

[截图:Mesh Renderer 的 Cast Shadows 和 Receive Shadows 设置]


11.7 后处理效果(Post-Processing)

11.7.1 什么是后处理

后处理是在 3D 场景渲染完成后,对最终图像应用的一系列视觉效果——就像照片拍完后用 Photoshop 或 Lightroom 调色。

💡 前端类比:后处理就像 CSS 的 filter 属性(blur()brightness()contrast()saturate())加上 backdrop-filter——但功能强大得多。

11.7.2 设置 Post-Processing

步骤 1:在 Camera 上启用后处理

  1. 选中 Main Camera
  2. 在 Camera 组件中勾选 Post Processing

[截图:Camera 组件中 Post Processing 复选框的位置]

步骤 2:创建 Post-Processing Volume

  1. Hierarchy → 右键 → VolumeGlobal Volume
  2. 在 Inspector 中点击 New 创建新的 Volume Profile

[截图:Global Volume 的 Inspector 面板]

步骤 3:添加效果

  1. 在 Volume Profile 中点击 Add Override
  2. 选择需要的效果

11.7.3 常用后处理效果

Bloom(辉光/泛光)

让高亮区域产生发光效果——营造梦幻、温暖的氛围。

Bloom 效果:

关闭 Bloom:              开启 Bloom:
┌──────────────┐          ┌──────────────┐
│      ●       │          │    ✨●✨      │
│   太阳       │          │  太阳发光扩散  │
│              │          │              │
│   🏮灯笼     │          │  🏮✨灯笼发光  │
└──────────────┘          └──────────────┘

[截图:Bloom 效果的开关对比]

Bloom 设置:
┌──────────────────────────────────┐
│ Threshold: 0.9                   │  ← 亮度阈值(超过此值才发光)
│ Intensity: 1.0                   │  ← 发光强度
│ Scatter: 0.7                     │  ← 扩散范围
│ Clamp: 65472                     │  ← 最大亮度限制
│ Tint: White                      │  ← 发光颜色色调
│ High Quality Filtering: ☑        │  ← 高质量滤波(手游可关)
└──────────────────────────────────┘

Color Grading(颜色分级/调色)

调整整体画面的颜色风格——就像给游戏加 Instagram 滤镜。

Color Grading 设置:
┌──────────────────────────────────┐
│ ===== White Balance =====        │
│ Temperature: 0                   │  ← 色温(正=暖,负=冷)
│ Tint: 0                         │  ← 色调(正=绿,负=品红)
│                                  │
│ ===== Tone Mapping =====         │
│ Mode: ACES                       │  ← ACES 电影级色调映射(推荐)
│                                  │
│ ===== Lift Gamma Gain =====      │
│ Lift:  暗部颜色调整              │
│ Gamma: 中间调颜色调整            │
│ Gain:  高光颜色调整              │
│                                  │
│ ===== Saturation =====           │
│ Post Exposure: 0                 │  ← 曝光调整
│ Contrast: 0                      │  ← 对比度 (-100 ~ 100)
│ Color Filter: White              │  ← 全局颜色滤镜
│ Saturation: 0                    │  ← 饱和度 (-100 ~ 100)
└──────────────────────────────────┘

Vignette(暗角)

画面边缘变暗——聚焦视觉中心,营造电影感。

Vignette 效果:
┌──────────────────┐
│ ░░░░░░░░░░░░░░░░ │
│ ░░░          ░░░ │
│ ░░    清晰    ░░ │
│ ░░   中心区   ░░ │
│ ░░░          ░░░ │
│ ░░░░░░░░░░░░░░░░ │
└──────────────────┘
   边缘逐渐变暗

设置:
  Intensity: 0.3   ← 暗角强度
  Smoothness: 0.3  ← 过渡平滑度
  Rounded: ☑       ← 圆形暗角

Ambient Occlusion(环境光遮蔽/AO)

让角落和接缝处变暗——增加细节感和深度感。

Ambient Occlusion 效果:

关闭 AO:                开启 AO:
┌────────┐              ┌────────┐
│        │              │        │
│  ┌──┐  │              │  ┌──┐  │
│  │  │  │              │▒▒│  │▒▒│  ← 角落处产生自然的阴影
│  └──┘  │              │▒▒└──┘▒▒│
│        │              │▒▒▒▒▒▒▒▒│
└────────┘              └────────┘

URP 中使用 SSAO(Screen Space Ambient Occlusion):
需要在 URP Renderer Data 中添加 SSAO Renderer Feature

在 URP 中启用 SSAO:

  1. 选中 URP Renderer Data 资产
  2. 在 Inspector 中点击 Add Renderer Feature
  3. 选择 Screen Space Ambient Occlusion
  4. 配置参数

[截图:URP Renderer Data 中添加 SSAO Renderer Feature 的操作步骤]

SSAO 设置:
┌──────────────────────────────────┐
│ Intensity: 1.0                   │  ← AO 强度
│ Radius: 0.035                    │  ← 采样半径
│ Falloff Distance: 100            │  ← 衰减距离
│ Quality: Medium                  │  ← 采样质量
│ Blur Quality: High               │  ← 模糊质量
│ After Opaque: ☑                  │
└──────────────────────────────────┘

Depth of Field(景深)

模拟相机对焦效果——前景或背景模糊。

Depth of Field 效果:

┌──────────────────────────────┐
│ ░░模糊░░  清晰对焦  ░░模糊░░ │
│ ░░前景░░  ← 主角 →  ░░背景░░ │
└──────────────────────────────┘
        近焦距    远焦距

DOF 模式:
  Gaussian(高斯):简单的模糊,性能好
  Bokeh(散景):真实的光圈散景效果,性能较重

设置(Gaussian):
  Start: 10        ← 开始模糊的距离
  End: 30          ← 完全模糊的距离

11.7.4 完整后处理设置代码

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

/// <summary>
/// 后处理效果运行时控制
///
/// 类比前端:类似动态修改 CSS filter 属性
/// element.style.filter = `blur(${value}px) brightness(${value})`;
///
/// 用途:
/// - 角色受伤时画面变红
/// - 进入水下时添加模糊和蓝色色调
/// - Boss 战时增加暗角和对比度
/// </summary>
public class PostProcessingController : MonoBehaviour
{
    [SerializeField] private Volume globalVolume;

    // 缓存各效果引用
    private Bloom bloom;
    private ColorAdjustments colorAdjustments;
    private Vignette vignette;
    private DepthOfField depthOfField;
    private ChromaticAberration chromaticAberration;

    void Start()
    {
        // 获取各后处理效果的引用
        VolumeProfile profile = globalVolume.profile;

        profile.TryGet(out bloom);
        profile.TryGet(out colorAdjustments);
        profile.TryGet(out vignette);
        profile.TryGet(out depthOfField);
        profile.TryGet(out chromaticAberration);
    }

    /// <summary>
    /// 角色受伤时的视觉效果
    /// 画面闪红 + 暗角加重 + 色差
    /// </summary>
    public void OnPlayerHit(float damage)
    {
        // 暗角加重
        if (vignette != null)
        {
            vignette.intensity.value = 0.5f;
            vignette.color.value = Color.red;
        }

        // 色差效果(画面边缘色彩分离)
        if (chromaticAberration != null)
        {
            chromaticAberration.intensity.value = 0.5f;
        }

        // 降低饱和度
        if (colorAdjustments != null)
        {
            colorAdjustments.saturation.value = -30f;
        }

        // 0.3 秒后恢复
        StartCoroutine(ResetHitEffect(0.3f));
    }

    /// <summary>
    /// 恢复受击效果
    /// </summary>
    private System.Collections.IEnumerator ResetHitEffect(float duration)
    {
        float elapsed = 0f;
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float t = elapsed / duration;

            if (vignette != null)
            {
                vignette.intensity.value = Mathf.Lerp(0.5f, 0.3f, t);
                vignette.color.value = Color.Lerp(Color.red, Color.black, t);
            }

            if (chromaticAberration != null)
            {
                chromaticAberration.intensity.value = Mathf.Lerp(0.5f, 0f, t);
            }

            if (colorAdjustments != null)
            {
                colorAdjustments.saturation.value = Mathf.Lerp(-30f, 0f, t);
            }

            yield return null;
        }
    }

    /// <summary>
    /// 进入水下时的视觉效果
    /// </summary>
    public void EnterUnderwater()
    {
        if (colorAdjustments != null)
        {
            // 蓝色色调
            colorAdjustments.colorFilter.value = new Color(0.5f, 0.7f, 1f);
            colorAdjustments.contrast.value = -20f;
        }

        if (bloom != null)
        {
            // 增加辉光,模拟水中光线散射
            bloom.intensity.value = 2f;
            bloom.threshold.value = 0.5f;
        }

        if (vignette != null)
        {
            vignette.intensity.value = 0.4f;
        }
    }

    /// <summary>
    /// 离开水下,恢复正常
    /// </summary>
    public void ExitUnderwater()
    {
        if (colorAdjustments != null)
        {
            colorAdjustments.colorFilter.value = Color.white;
            colorAdjustments.contrast.value = 0f;
        }

        if (bloom != null)
        {
            bloom.intensity.value = 1f;
            bloom.threshold.value = 0.9f;
        }

        if (vignette != null)
        {
            vignette.intensity.value = 0.3f;
        }
    }

    /// <summary>
    /// 暂停游戏时的景深模糊效果
    /// 模拟对焦在 UI 菜单上,游戏画面模糊
    /// </summary>
    public void SetPauseBlur(bool paused)
    {
        if (depthOfField != null)
        {
            depthOfField.active = paused;
            if (paused)
            {
                depthOfField.mode.value = DepthOfFieldMode.Gaussian;
                depthOfField.gaussianStart.value = 0f;
                depthOfField.gaussianEnd.value = 5f;
            }
        }
    }
}

11.8 Shader Graph 基础

11.8.1 什么是 Shader

Shader(着色器)是运行在 GPU 上的程序,决定了每个像素的最终颜色——包括光照计算、纹理采样、特殊效果等。

💡 前端类比:Shader 就像 CSS,但是用来控制 3D 物体的外观。如果你用过 WebGL 的 GLSL,Unity 的 Shader 概念完全相同。Shader Graph 就是 Shader 的可视化编辑器——类似 Figma 对设计的降低门槛。

11.8.2 创建 Shader Graph

  1. Project 窗口右键 → CreateShader GraphURPLit Shader Graph
  2. 命名为 EmissivePulse(发光脉冲效果)
  3. 双击打开 Shader Graph 编辑器

[截图:Shader Graph 编辑器的完整界面,标注主要区域——Graph Inspector(左)、Node 编辑区(中)、Master Stack(右)]

11.8.3 Shader Graph 节点类型

Shader Graph 常用节点分类:

Input(输入):
  ├── Time           ← 时间(用于动画)
  ├── UV             ← 纹理坐标
  ├── Position       ← 顶点位置
  ├── Normal         ← 法线方向
  └── Property       ← 自定义属性(在 Inspector 中可调)

Math(数学):
  ├── Add / Subtract / Multiply / Divide
  ├── Lerp           ← 线性插值
  ├── Sine / Cosine  ← 三角函数
  ├── Clamp          ← 限制范围
  └── Remap          ← 值域映射

Texture(纹理):
  ├── Sample Texture 2D  ← 采样 2D 纹理
  ├── Tiling And Offset  ← 平铺和偏移
  └── Normal Unpack      ← 解包法线贴图

Channel(通道):
  ├── Split            ← 拆分 RGBA 通道
  └── Combine          ← 合并通道

Artistic(艺术):
  ├── Blend            ← 混合模式
  └── Contrast / Saturation

11.8.4 实战:创建发光脉冲 Shader

效果:物体周期性地发光和暗灭,常用于可拾取的道具。

Shader Graph 节点连接图:

[Time] ──→ [Multiply ×2π] ──→ [Sine] ──→ [Remap (−1,1)→(0,1)]

[Emission Color] ──→ [Multiply] ←────────────┘


                   Fragment: Emission

[Base Color] ──→ Fragment: Base Color
[Normal Map] ──→ Fragment: Normal
[Metallic]   ──→ Fragment: Metallic
[Smoothness] ──→ Fragment: Smoothness

步骤:

  1. 创建属性(Property):

    • BaseColor(Color):基础颜色
    • EmissionColor(Color,HDR):发光颜色
    • PulseSpeed(Float,默认 2):脉冲速度
    • EmissionIntensity(Float,默认 3):发光强度
  2. 搭建节点网络:

    • Time 节点 → Multiply (PulseSpeed) → Sine → Remap (-1,1 → 0,1)
    • Remap 输出 → Multiply (EmissionColor) → Multiply (EmissionIntensity)
    • 最终结果连接到 Fragment 的 Emission 端口
  3. 保存 Shader Graph(Ctrl+S / Cmd+S)

[截图:完成的 Shader Graph 节点网络]

  1. 创建材质:
    • Project 右键 → Create → Material
    • Shader 选择刚创建的 EmissivePulse
    • 在 Inspector 中调整属性

[截图:使用 EmissivePulse 材质的道具在 Scene 中的发光效果]


11.9 材质与纹理系统

11.9.1 PBR 材质基础

URP 默认使用 PBR(Physically Based Rendering) 材质系统——基于物理的渲染。

PBR 材质通道:

┌──────────────────────────────────────────────┐
│ Material(材质)= 多张纹理贴图的组合          │
│                                              │
│ ┌──────────┐  Base Map (Albedo)             │
│ │ 🎨       │  基础颜色贴图                   │
│ │ 颜色/纹理 │  定义物体的颜色和图案            │
│ └──────────┘  类比:CSS background-color     │
│                                              │
│ ┌──────────┐  Normal Map (法线贴图)          │
│ │ 🗺️       │  蓝紫色的凹凸信息               │
│ │ 凹凸细节  │  不改变几何体,只改变光照细节     │
│ └──────────┘  类比:CSS 的 box-shadow 细节    │
│                                              │
│ ┌──────────┐  Metallic Map (金属度)          │
│ │ ⬛⬜     │  黑白贴图                        │
│ │ 金属度    │  白 = 金属(如铁、金)            │
│ └──────────┘  黑 = 非金属(如木头、塑料)      │
│                                              │
│ ┌──────────┐  Smoothness (光滑度)            │
│ │ 🪞       │  表面光滑程度                    │
│ │ 光滑/粗糙 │  1 = 镜面(玻璃)               │
│ └──────────┘  0 = 粗糙(石头)                │
│                                              │
│ ┌──────────┐  Emission Map (自发光)          │
│ │ ✨       │  自发光区域和颜色                │
│ │ 发光      │  用于霓虹灯、屏幕、魔法效果      │
│ └──────────┘  配合 Bloom 后处理效果           │
│                                              │
│ ┌──────────┐  Occlusion Map (AO 贴图)       │
│ │ 🌑       │  预烘焙的环境光遮蔽              │
│ │ 角落阴影  │  角落和缝隙处变暗                │
│ └──────────┘  增加细节真实感                   │
└──────────────────────────────────────────────┘

11.9.2 URP Lit Shader 属性

[截图:URP Lit 材质的完整 Inspector 面板,标注各个贴图槽位]

URP/Lit Shader 完整属性:

┌──────────────────────────────────────────────┐
│ ===== Surface Options =====                   │
│                                              │
│ Surface Type: Opaque / Transparent           │
│ Render Face: Front / Back / Both             │
│ Alpha Clipping: ☐                            │
│                                              │
│ ===== Surface Inputs =====                    │
│                                              │
│ Base Map: [纹理] × [颜色]                    │  ← Albedo
│ Metallic Map: [纹理]                         │  ← 金属度
│   Metallic: 0.0 ━━━━━━━━━━━━━ 1.0           │
│   Smoothness: 0.0 ━━━━━━━●━━━ 1.0           │
│                                              │
│ Normal Map: [纹理]                           │  ← 法线贴图
│   Normal Strength: 1.0                       │
│                                              │
│ Occlusion Map: [纹理]                        │  ← AO 贴图
│                                              │
│ Emission: ☐                                  │
│   Emission Map: [纹理] × [HDR 颜色]         │
│   Emission Intensity: 1.0                    │
│                                              │
│ ===== Advanced =====                          │
│                                              │
│ Specular Highlights: ☑                       │
│ Environment Reflections: ☑                   │
│ Receive Shadows: ☑                           │
│ GPU Instancing: ☑                            │  ← 开启 GPU 实例化
└──────────────────────────────────────────────┘

11.9.3 纹理导入设置

纹理导入设置推荐(手游):

┌──────────────────────────────────────┐
│ Texture Type:                        │
│   Default        ← 普通贴图         │
│   Normal map     ← 法线贴图         │
│   Sprite (2D)    ← 2D/UI 用        │
│                                      │
│ Max Size: 1024                       │  ← 手游推荐最大 1024-2048
│                                      │
│ Compression:                         │
│   ASTC 6x6      ← iOS/Android 推荐 │
│                                      │
│ Generate Mip Maps: ☑                 │  ← 远处使用低精度纹理
│                                      │     提升性能和减少摩尔纹
│                                      │
│ sRGB (Color Texture): ☑              │  ← 颜色贴图开启
│                                      │     法线贴图关闭
│                                      │
│ Filter Mode: Bilinear               │  ← 过滤模式
│ Aniso Level: 1                       │  ← 各向异性过滤级别
└──────────────────────────────────────┘

11.9.4 材质设置代码

using UnityEngine;

/// <summary>
/// 运行时材质属性控制
/// 类比前端:element.style.backgroundColor = 'red';
///
/// 注意:直接修改 renderer.material 会创建材质实例(增加内存)
/// 如果多个物体共用一个材质,应该使用 MaterialPropertyBlock
/// </summary>
public class MaterialController : MonoBehaviour
{
    private Renderer meshRenderer;
    private MaterialPropertyBlock propertyBlock;

    // Shader 属性 ID(预计算,类似 Animator 参数哈希)
    private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
    private static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor");
    private static readonly int SmoothnessId = Shader.PropertyToID("_Smoothness");
    private static readonly int MetallicId = Shader.PropertyToID("_Metallic");

    void Start()
    {
        meshRenderer = GetComponent<Renderer>();
        propertyBlock = new MaterialPropertyBlock();
    }

    /// <summary>
    /// 使用 MaterialPropertyBlock 修改材质属性(推荐方式)
    /// 不会创建材质实例,性能更好
    /// </summary>
    public void SetColor(Color color)
    {
        meshRenderer.GetPropertyBlock(propertyBlock);
        propertyBlock.SetColor(BaseColorId, color);
        meshRenderer.SetPropertyBlock(propertyBlock);
    }

    /// <summary>
    /// 设置发光颜色和强度
    /// </summary>
    public void SetEmission(Color color, float intensity)
    {
        meshRenderer.GetPropertyBlock(propertyBlock);
        // HDR 颜色 = 颜色 × 强度(超过 1 的值会触发 Bloom)
        Color hdrColor = color * intensity;
        propertyBlock.SetColor(EmissionColorId, hdrColor);
        meshRenderer.SetPropertyBlock(propertyBlock);
    }

    /// <summary>
    /// 设置金属度和光滑度
    /// </summary>
    public void SetMetallic(float metallic, float smoothness)
    {
        meshRenderer.GetPropertyBlock(propertyBlock);
        propertyBlock.SetFloat(MetallicId, metallic);
        propertyBlock.SetFloat(SmoothnessId, smoothness);
        meshRenderer.SetPropertyBlock(propertyBlock);
    }

    /// <summary>
    /// 角色受伤时闪白效果
    /// </summary>
    public void FlashWhite(float duration = 0.1f)
    {
        StartCoroutine(FlashCoroutine(duration));
    }

    private System.Collections.IEnumerator FlashCoroutine(float duration)
    {
        SetColor(Color.white);
        yield return new WaitForSeconds(duration);
        SetColor(Color.white); // 恢复原色(根据实际项目调整)
    }
}

11.10 URP Renderer Features

11.10.1 什么是 Renderer Feature

Renderer Features 允许你在 URP 渲染流程中插入自定义的渲染步骤——相当于在渲染管线中安装”插件”。

💡 前端类比:Renderer Features 类似 Webpack 的 Plugin——在构建(渲染)流程的特定阶段插入自定义逻辑。

11.10.2 添加 Renderer Feature

  1. 选中 URP Renderer Data 资产(URP-Pipeline_Renderer.asset
  2. Inspector 底部点击 Add Renderer Feature
  3. 选择需要的 Feature

[截图:Add Renderer Feature 的下拉菜单,显示可用的 Feature 列表]

内置 Renderer Features:

Feature用途
Screen Space Ambient OcclusionSSAO 环境光遮蔽
Decal贴花(弹孔、污渍等)
Render Objects在特定阶段渲染特定 Layer 的物体
Full Screen Pass全屏后处理效果

11.10.3 使用 Render Objects 实现角色描边

一个常见需求:在角色周围添加描边效果(卡通风格)。

步骤:

  1. 创建描边材质:
    • 新建材质,使用 Unlit Shader
    • 设置颜色为黑色或你需要的描边颜色
  2. 在 Renderer Data 中添加 Render Objects Feature
  3. 配置:
    • Event: BeforeRenderingOpaques
    • Layer Mask: 选择角色所在的 Layer
    • Override Material: 描边材质
    • Override → Depth: Write = On, Test = Less Equal

[截图:Render Objects Feature 配置描边效果的参数]


11.11 Camera Stacking(相机堆叠)

11.11.1 为什么需要相机堆叠

有时候你需要用不同的设置渲染不同的内容层。

相机堆叠的典型场景:

Base Camera(基础相机):
  渲染 3D 游戏世界

  ┌────────────────────────┐
  │  🏔️ 天空               │
  │    🌳🏠🌳              │
  │      🧍                │
  │  🌿🌿🌿🌿              │
  └────────────────────────┘
         ↑ 叠加
Overlay Camera(覆盖相机):
  渲染 UI 或特殊效果

  ┌────────────────────────┐
  │ [HP ████████]    12:30 │
  │                        │
  │                        │
  │              [小地图]   │
  └────────────────────────┘
         ↑ 叠加
Overlay Camera 2:
  渲染武器模型(独立 FOV)

  ┌────────────────────────┐
  │                        │
  │                        │
  │                  🔫    │
  │                        │
  └────────────────────────┘

11.11.2 设置 Camera Stacking

步骤 1:设置 Base Camera

  1. 选中 Main Camera
  2. Render Type 设为 Base
  3. Stack 列表中添加 Overlay Camera

步骤 2:创建 Overlay Camera

  1. 创建新 Camera
  2. Render Type 设为 Overlay
  3. 设置只渲染需要的 Layer
  4. Clear Flags 设为 Don't Clear(不清除背景,透明叠加)

[截图:Base Camera 的 Stack 列表中添加了 Overlay Camera]

using UnityEngine;
using UnityEngine.Rendering.Universal;

/// <summary>
/// 运行时控制 Camera Stack
/// </summary>
public class CameraStackController : MonoBehaviour
{
    [SerializeField] private Camera baseCamera;
    [SerializeField] private Camera uiOverlayCamera;
    [SerializeField] private Camera weaponOverlayCamera;

    void Start()
    {
        // 获取 Base Camera 的 URP 数据
        var cameraData = baseCamera.GetUniversalAdditionalCameraData();

        // 添加 Overlay Camera 到 Stack
        cameraData.cameraStack.Add(uiOverlayCamera);
        cameraData.cameraStack.Add(weaponOverlayCamera);
    }

    /// <summary>
    /// 进入菜单时禁用武器相机
    /// </summary>
    public void EnterMenu()
    {
        weaponOverlayCamera.gameObject.SetActive(false);
    }

    /// <summary>
    /// 退出菜单时启用武器相机
    /// </summary>
    public void ExitMenu()
    {
        weaponOverlayCamera.gameObject.SetActive(true);
    }
}

11.12 实战:完整的场景光照设置

11.12.1 场景光照配置步骤

以一个户外开放世界场景为例,完整的光照设置流程:

步骤清单:

1. ☐ 环境光照设置
   Project Settings → Lighting → Environment
   - Skybox Material: 选择天空盒
   - Environment Lighting Source: Skybox
   - Ambient Intensity: 1

2. ☐ 主方向光(太阳)
   - Color: 暖白色 #FFF5E0
   - Intensity: 1.5
   - Shadow Type: Soft Shadows
   - Mode: Mixed (需要烘焙间接光 + 实时阴影)

3. ☐ 补光(Fill Light,可选)
   - 第二个 Directional Light,弱强度
   - 方向与太阳相反(减少纯黑阴影)
   - 不投射阴影
   - Intensity: 0.2

4. ☐ 标记静态物体
   - 选中所有不会移动的物体
   - 勾选 Static → Contribute GI

5. ☐ 放置 Light Probes
   - 在角色活动区域放置
   - 光照变化大的地方密集排列

6. ☐ 放置 Reflection Probes
   - 水面附近
   - 室内环境
   - 金属/光滑建筑物旁

7. ☐ 烘焙光照
   - Lightmapper: Progressive GPU
   - Resolution: 20(开发阶段用 10)
   - Bounces: 2
   - 点击 Generate Lighting

8. ☐ 后处理设置
   - 创建 Global Volume
   - 添加 Bloom、Color Grading、Vignette
   - 调整参数至满意

9. ☐ 性能检查
   - 查看 Stats 窗口的 Draw Calls
   - 在目标设备上测试帧率

11.12.2 环境设置代码

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

/// <summary>
/// 环境光照和氛围控制器
/// 管理天空盒、雾效、环境光等
/// </summary>
public class EnvironmentController : MonoBehaviour
{
    [Header("天空盒")]
    [SerializeField] private Material daySkybox;
    [SerializeField] private Material nightSkybox;

    [Header("雾效")]
    [SerializeField] private Color dayFogColor = new Color(0.7f, 0.8f, 0.9f);
    [SerializeField] private Color nightFogColor = new Color(0.05f, 0.05f, 0.15f);
    [SerializeField] private float fogDensity = 0.01f;

    [Header("环境光")]
    [SerializeField] private Color dayAmbientColor = new Color(0.5f, 0.5f, 0.6f);
    [SerializeField] private Color nightAmbientColor = new Color(0.05f, 0.05f, 0.1f);

    /// <summary>
    /// 根据时间更新环境
    /// </summary>
    /// <param name="dayNightRatio">昼夜比例 0=夜晚 1=白天</param>
    public void UpdateEnvironment(float dayNightRatio)
    {
        float t = Mathf.Clamp01(dayNightRatio);

        // 更新雾效
        RenderSettings.fogColor = Color.Lerp(nightFogColor, dayFogColor, t);
        RenderSettings.fogDensity = fogDensity;
        RenderSettings.fog = true;

        // 更新环境光
        RenderSettings.ambientLight = Color.Lerp(
            nightAmbientColor, dayAmbientColor, t);

        // 天空盒过渡(使用材质混合或切换)
        if (t > 0.5f)
        {
            RenderSettings.skybox = daySkybox;
        }
        else
        {
            RenderSettings.skybox = nightSkybox;
        }
    }

    /// <summary>
    /// 设置雾效参数
    /// </summary>
    public void SetFog(bool enabled, Color color, float density)
    {
        RenderSettings.fog = enabled;
        RenderSettings.fogColor = color;
        RenderSettings.fogMode = FogMode.Exponential;
        RenderSettings.fogDensity = density;
    }
}

11.13 本章小结

URP 光照与渲染知识图谱:

URP 渲染管线
├── Pipeline Asset 配置
│   ├── 渲染质量(MSAA、Render Scale)
│   ├── 光照设置(Per Pixel / Per Vertex)
│   ├── 阴影设置(距离、级联、分辨率)
│   └── 多个画质 Preset(Low/Medium/High)

├── 光源系统
│   ├── Directional Light(太阳)
│   ├── Point Light(灯泡)
│   ├── Spot Light(手电筒)
│   ├── Area Light(窗户,仅烘焙)
│   └── 光源模式(Realtime / Mixed / Baked)

├── 光照烘焙
│   ├── Lightmap(光照贴图)
│   ├── Light Probe(动态物体间接光照)
│   ├── Reflection Probe(环境反射)
│   └── Static 标记

├── 阴影系统
│   ├── Shadow Resolution
│   ├── Shadow Distance
│   ├── Shadow Cascades
│   └── Per-Object Shadow Settings

├── 后处理(Post-Processing)
│   ├── Bloom(辉光)
│   ├── Color Grading(调色)
│   ├── Vignette(暗角)
│   ├── SSAO(环境光遮蔽)
│   ├── Depth of Field(景深)
│   └── 运行时动态控制

├── 材质系统
│   ├── PBR 贴图(Albedo / Normal / Metallic / Emission)
│   ├── URP/Lit Shader
│   ├── MaterialPropertyBlock(性能优化)
│   └── Shader Graph(可视化 Shader 编辑器)

├── Renderer Features
│   ├── SSAO
│   ├── Decal
│   └── Render Objects(自定义渲染)

└── Camera Stacking
    ├── Base Camera(基础渲染)
    └── Overlay Camera(UI、武器等覆盖层)

关键要点回顾:

  1. 手游用 URP——性能和画质的最佳平衡
  2. 大量使用烘焙光照——手游的间接光照必须预计算
  3. Light Probe 是动态物体的生命线——没有它角色会”与环境脱节”
  4. 后处理是点睛之笔——Bloom + Color Grading + Vignette 三件套大幅提升画面质感
  5. MaterialPropertyBlock——修改材质属性的正确方式(而不是直接修改 material)
  6. 创建多个画质预设——让玩家可以根据设备性能选择

练习题

练习 1:室内光照(难度:⭐⭐)

创建一个简单的室内场景(用 Cube 搭建房间):

  • 一个方向光作为窗户透入的光线
  • 两个 Point Light 作为室内灯(暖色调)
  • 烘焙光照(标记所有墙壁和地板为 Static)
  • 放置 Light Probes 和 Reflection Probe
  • 观察角色在室内的间接光照效果

练习 2:昼夜循环(难度:⭐⭐⭐)

实现一个基本的昼夜循环系统:

  • 太阳(Directional Light)绕 X 轴旋转,模拟日升日落
  • 根据时间动态调整太阳颜色和强度
  • 环境光和雾效随时间变化
  • 添加一个简单的 UI 显示当前时间
  • 提示:参考 11.3.4 节的 DynamicLightController

练习 3:后处理效果切换(难度:⭐⭐)

创建三种视觉风格,通过按键切换:

  • 标准模式:Bloom + 轻微暗角
  • 夜视模式:绿色色调 + 高亮度 + 噪点
  • 受伤模式:红色暗角 + 低饱和度 + 色差 提示:可以创建多个 Volume Profile 或在代码中动态修改参数。

练习 4:Shader Graph 练习(难度:⭐⭐⭐)

使用 Shader Graph 创建以下效果之一:

  • 水面 Shader:透明 + UV 流动 + 法线扰动
  • 溶解 Shader:从下到上逐渐消融(使用噪声纹理 + Clip)
  • 全息投影 Shader:半透明 + 扫描线 + 边缘发光 提示:善用 Time 节点制作动画效果。

下一章预告

第 12 章:背包与物品系统 将学习:

  • ScriptableObject 数据驱动设计
  • 背包数据结构(物品数据库、堆叠、排序)
  • 物品拾取与丢弃
  • 背包 UI(Grid Layout + 拖拽交互)
  • 装备系统基础
  • 开始构建真正的游戏玩法系统!

版权声明:本教程为 BellLab 原创内容,仅供学习使用。

目录