第 11 章:URP 光照与渲染管线
第 11 章:URP 光照与渲染管线
前端类比:如果把游戏画面比作一个网页,那么渲染管线(Render Pipeline)就是浏览器的渲染引擎,光照是 CSS 的
filter和box-shadow,后处理效果是 Instagram 滤镜,而 Shader 就是 WebGL Shader——你可能写过mix-blend-mode和backdrop-filter,但 Unity 的渲染系统远比 CSS 强大和复杂。
本章目标
完成本章后,你将能够:
- 理解 URP(Universal Render Pipeline)的架构和配置
- 配置 URP Pipeline Asset 的各项参数
- 掌握四种光源类型及其适用场景
- 区分实时光照与烘焙光照,合理选择
- 理解 Lightmap 光照贴图的烘焙流程
- 使用 Reflection Probe 和 Light Probe 优化动态物体光照
- 正确配置阴影系统(分辨率、距离、级联)
- 使用 Post-Processing Volume 添加视觉效果
- 入门 Shader Graph(创建简单的自定义 Shader)
- 理解 PBR 材质系统(Albedo、Normal Map、Metallic、Emission)
- 配置 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-in | Built-in Render Pipeline | 旧版默认管线 | 通用(遗留项目) |
| URP | Universal Render Pipeline | 性能优先的通用管线 | 移动端 + PC + 主机 |
| HDRP | High Definition Render Pipeline | 画质优先的高端管线 | 高端 PC + 主机 |
选择渲染管线的决策:
开发手游?
├── 是 → URP(本教程使用)
│ 性能优秀,功能够用
│
└── 否 → 追求 3A 画质?
├── 是 → HDRP
│ 适合高端平台
│
└── 否 → URP(大多数情况最佳选择)
🎯 最佳实践:对于手游开发,始终选择 URP。它在保证画面质量的同时,对移动端 GPU 做了大量优化。
11.1.3 URP vs Built-in 的主要区别
| 方面 | Built-in | URP |
|---|---|---|
| Shader 语言 | Surface Shader / HLSL | Shader 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 包
- 菜单 →
Window→Package Manager - 搜索
Universal RP - 点击
Install
步骤 2:创建 URP Pipeline Asset
- Project 窗口右键 →
Create→Rendering→URP Asset (with Universal Renderer) - 这会创建两个文件:
URP-Pipeline.asset(Pipeline Asset)URP-Pipeline_Renderer.asset(Renderer Data)
[截图:Project 窗口中新创建的 URP Pipeline Asset 和 Renderer Data]
步骤 3:应用 URP Pipeline
- 菜单 →
Edit→Project Settings→Graphics - 将
Scriptable Render Pipeline Settings设为刚创建的URP-Pipeline.asset
[截图:Graphics Settings 中设置 Scriptable Render Pipeline Settings]
步骤 4:升级材质
- 菜单 →
Edit→Rendering→Materials→Convert Built-in Materials to URP - 这会把旧的 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: ☑ │
└────────────────────────────────────────────┘
手游推荐设置:
| 设置项 | 低端机 | 中端机 | 高端机 |
|---|---|---|---|
| MSAA | Off | 2x | 4x |
| Render Scale | 0.65 | 0.85 | 1.0 |
| Additional Lights Mode | Per Vertex | Per Pixel | Per Pixel |
| Per Object Limit | 2 | 4 | 8 |
| Shadow Distance | 30 | 50 | 100 |
| Shadow Cascades | 1 | 2 | 4 |
| Shadow Resolution | 512 | 1024 | 2048 |
🎯 最佳实践:创建多个 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 面板,标注各属性]
| 属性 | Directional | Point | Spot | Area |
|---|---|---|---|---|
| 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 的物体才能接收烘焙光照。
- 选中场景中的静态物体(地面、建筑、石头等)
- 在 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 烘焙光照贴图
- 菜单 →
Window→Rendering→Lighting - 在 Lighting 窗口中切换到
Baked Lightmaps标签 - 配置烘焙参数
[截图: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
└──────────────────────────────────────┘
- 点击
Generate Lighting开始烘焙 - 烘焙完成后,会在场景同名文件夹下生成 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
- Hierarchy → 右键 →
Light→Light Probe Group - 在 Scene 视图中选中 Light Probe Group
- 在 Inspector 中点击
Edit Light Probes进入编辑模式 - 添加/删除/移动探针点
[截图:场景中的 Light Probe Group,显示黄色探针点和连线]
Light Probe 放置原则:
好的放置: 不好的放置:
● ● ● ●●●●●●●●●●●●
● ● 太多太密——浪费
● ● ●
在光照变化的地方 ● ●
密度更高 太少太稀——无法表达
光照变化
推荐:
- 门口、窗户附近密一些(光照变化大)
- 走廊、过渡区域密一些
- 开阔空地疏一些
- 角色不会到达的地方不放
11.5.3 放置 Reflection Probe
- Hierarchy → 右键 →
Light→Reflection Probe - 调整 Probe 的 Box Size 覆盖需要的区域
- 设置 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 上启用后处理
- 选中 Main Camera
- 在 Camera 组件中勾选
Post Processing
[截图:Camera 组件中 Post Processing 复选框的位置]
步骤 2:创建 Post-Processing Volume
- Hierarchy → 右键 →
Volume→Global Volume - 在 Inspector 中点击
New创建新的 Volume Profile
[截图:Global Volume 的 Inspector 面板]
步骤 3:添加效果
- 在 Volume Profile 中点击
Add Override - 选择需要的效果
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:
- 选中 URP Renderer Data 资产
- 在 Inspector 中点击
Add Renderer Feature - 选择
Screen Space Ambient Occlusion - 配置参数
[截图: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
- Project 窗口右键 →
Create→Shader Graph→URP→Lit Shader Graph - 命名为
EmissivePulse(发光脉冲效果) - 双击打开 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
步骤:
-
创建属性(Property):
BaseColor(Color):基础颜色EmissionColor(Color,HDR):发光颜色PulseSpeed(Float,默认 2):脉冲速度EmissionIntensity(Float,默认 3):发光强度
-
搭建节点网络:
- Time 节点 → Multiply (PulseSpeed) → Sine → Remap (-1,1 → 0,1)
- Remap 输出 → Multiply (EmissionColor) → Multiply (EmissionIntensity)
- 最终结果连接到 Fragment 的 Emission 端口
-
保存 Shader Graph(Ctrl+S / Cmd+S)
[截图:完成的 Shader Graph 节点网络]
- 创建材质:
- 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
- 选中 URP Renderer Data 资产(
URP-Pipeline_Renderer.asset) - Inspector 底部点击
Add Renderer Feature - 选择需要的 Feature
[截图:Add Renderer Feature 的下拉菜单,显示可用的 Feature 列表]
内置 Renderer Features:
| Feature | 用途 |
|---|---|
| Screen Space Ambient Occlusion | SSAO 环境光遮蔽 |
| Decal | 贴花(弹孔、污渍等) |
| Render Objects | 在特定阶段渲染特定 Layer 的物体 |
| Full Screen Pass | 全屏后处理效果 |
11.10.3 使用 Render Objects 实现角色描边
一个常见需求:在角色周围添加描边效果(卡通风格)。
步骤:
- 创建描边材质:
- 新建材质,使用
UnlitShader - 设置颜色为黑色或你需要的描边颜色
- 新建材质,使用
- 在 Renderer Data 中添加
Render ObjectsFeature - 配置:
- Event:
BeforeRenderingOpaques - Layer Mask: 选择角色所在的 Layer
- Override Material: 描边材质
- Override → Depth: Write = On, Test = Less Equal
- Event:
[截图: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
- 选中 Main Camera
- Render Type 设为
Base - 在
Stack列表中添加 Overlay Camera
步骤 2:创建 Overlay Camera
- 创建新 Camera
- Render Type 设为
Overlay - 设置只渲染需要的 Layer
- 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、武器等覆盖层)
关键要点回顾:
- 手游用 URP——性能和画质的最佳平衡
- 大量使用烘焙光照——手游的间接光照必须预计算
- Light Probe 是动态物体的生命线——没有它角色会”与环境脱节”
- 后处理是点睛之笔——Bloom + Color Grading + Vignette 三件套大幅提升画面质感
- MaterialPropertyBlock——修改材质属性的正确方式(而不是直接修改 material)
- 创建多个画质预设——让玩家可以根据设备性能选择
练习题
练习 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 原创内容,仅供学习使用。