描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302613282
Unity引擎提供的一系列卓越功能可以帮助开发 者构建高性能的游戏。本书引导读者优化游戏开发中的方方面面,从游戏角色到脚本,一直到动画优化。
在本书中,读者将学习提高游戏脚本质量的代码编写技术,学习如何使用E C S和Burs t编译器等Unity技术优化游戏。本书将助力读者使用Unity生态系统管理第三方工具,引导读者解决Unity大型游戏和V R游戏中的性能问题,帮助读者检测性能问题并分析性能根源。随着阅读的深入,读者将学习Unity C#脚本代码的最佳实践并掌握使用模式,之后会掌握优化音频资源和纹理文件,以及高效地存储和使用资源文件。然后,读者将了解渲染管线并学习如何识别管线中的性能问题。此外,读者还将学习如何优化内存以及Unity的处理器单元。最后,读者将获得Unity专家用于提升项目工作流的提示和技巧。
阅读本书,读者将提升使用Unity及其组件构建交互式游戏所需的技能。
主要内容:
使用Unity Profiler发现程序中的瓶颈并找到解决方法
发现VR项目中关键的性能问题,并学习如何处理它们
以易用的方式增强着色器,通过细微而有效的性能调整优化它们
使用物理引擎使场景尽可能动态化
组织、过滤和压缩艺术资源,在保持高品质的同时实现性能最大化
使用Mono框架和C#实现内存利用最大化,以及优化GC
第Ⅰ部分 基本的脚本优化
第1章 研究性能问题 2
1.1 使用Unity Profiler收集分析数据 3
1.1.1 启动Profiler 4
1.1.2 Profiler窗口 8
1.2 性能分析的最佳方法 17
1.2.1 验证脚本是否存在 18
1.2.2 验证脚本次数 18
1.2.3 验证事件的顺序 19
1.2.4 最小化正在进行的代码更改 20
1.2.5 最小化内部影响 20
1.2.6 最小化外部影响 22
1.2.7 代码片段的针对性
分析 22
1.3 关于分析的思考 26
1.3.1 理解Profiler工具 27
1.3.2 减少干扰 27
1.3.3 关注问题 28
1.4 本章小结 28
第2章 脚本策略 29
2.1 使用最快的方法获取组件 30
2.2 移除空的回调定义 31
2.3 缓存组件引用 34
2.4 共享计算输出 35
2.5 Update、Coroutines和InvokeRepeating 36
2.6 更快的GameObject空引用检查 39
2.7 避免从GameObject中检索字符串属性 40
2.8 使用合适的数据结构 42
2.9 避免在运行时修改
Transform的父节点 43
2.10 关注缓存Transform的 变化 44
2.11 避免在运行时使用Find()和 SendMessage()方法 45
2.11.1 将引用分配给预先
存在的对象 48
2.11.2 静态类 50
2.11.3 单例组件 52
2.11.4 全局消息传递系统 56
2.12 禁用未使用的脚本和 对象 66
2.12.1 通过可见性禁用对象 66
2.12.2 通过距离禁用对象 67
2.13 使用距离的平方而不是 距离 68
2.14 最小化反序列化行为 69
2.14.1 减小序列化对象 70
2.14.2 异步加载序列化对象 70
2.14.3 在内存中保存之前加载的序列化对象 70
2.14.4 将公共数据移入ScriptableObject 71
2.15 叠加、异步地加载
场景 71
2.16 创建自定义的
Update()层 72
2.17 本章小结 76
第Ⅱ部分 图形优化
第3章 批处理的优势 78
3.1 Draw Call 79
3.2 材质和着色器 81
3.3 Frame Debugger 83
3.4 动态批处理 85
3.4.1 顶点属性 86
3.4.2 网格缩放 87
3.4.3 动态批处理总结 88
3.5 静态批处理 89
3.5.1 Static标记 89
3.5.2 内存需求 90
3.5.3 材质引用 90
3.5.4 静态批处理的警告 90
3.5.5 静态批处理总结 91
3.6 本章小结 92
第4章 优化艺术资源 93
4.1 音频文件 93
4.1.1 导入音频文件 94
4.1.2 加载音频文件 94
4.1.3 编码格式与品质级别 97
4.1.4 音频性能增强 98
4.2 纹理文件 101
4.2.1 纹理压缩格式 101
4.2.2 纹理性能增强 103
4.3 网格和动画文件 111
4.3.1 减少多边形数量 112
4.3.2 调整网格压缩 112
4.3.3 恰当使用Read-Write
Enabled 112
4.3.4 考虑烘焙动画 113
4.3.5 合并网格 113
4.4 Asset Bundle和Resource 114
4.5 本章小结 115
第5章 加速物理引擎 116
5.1 物理引擎的内部工作情况 117
5.1.1 物理和时间 117
5.1.2 静态碰撞器和动态碰撞器 120
5.1.3 碰撞检测 121
5.1.4 碰撞器类型 122
5.1.5 碰撞矩阵 124
5.1.6 Rigidbody激活和休眠状态 124
5.1.7 射线和对象投射 125
5.1.8 调试物理 125
5.2 物理性能优化 127
5.2.1 场景设置 127
5.2.2 适当使用静态碰撞器 129
5.2.3 恰当使用触发体积 129
5.2.4 优化碰撞矩阵 130
5.2.5 首选离散碰撞检测 131
5.2.6 修改固定更新频率 132
5.2.7 调整允许的最大时间步长 133
5.2.8 最小化射线投射和边界体积检查 133
5.2.9 避免复杂的网格碰撞器 135
5.2.10 避免复杂的物理组件 137
5.2.11 使物理对象休眠 137
5.2.12 修改处理器迭代次数 138
5.2.13 优化布娃娃 139
5.2.14 确定何时使用物理 141
5.3 本章小结 142
第6章 动态图形 143
6.1 管线渲染 144
6.1.1 GPU前端 145
6.1.2 GPU后端 146
6.1.3 光照和阴影 149
6.1.4 多线程渲染 152
6.1.5 低级渲染API 153
6.2 性能检测问题 153
6.2.1 分析渲染问题 153
6.2.2 暴力测试 155
6.3 渲染性能的增强 157
6.3.1 启用/禁用GPU Skinning 157
6.3.2 降低几何复杂度 157
6.3.3 减少曲面细分 157
6.3.4 应用GPU实例化 158
6.3.5 使用基于网格的LOD 159
6.3.6 使用遮挡剔除 160
6.3.7 优化粒子系统 161
6.3.8 优化Unity UI 163
6.3.9 着色器优化 167
6.3.10 使用更少的纹理数据 173
6.3.11 测试不同的GPU纹理压缩格式 174
6.3.12 最小化纹理交换 174
6.3.13 VRAM限制 175
6.3.14 照明优化 176
6.3.15 优化移动设备的渲染
性能 178
6.4 本章小结 180
第Ⅲ部分 高级优化
第7章 虚拟现实和增强现实的优化 182
7.1 XR技术概述 182
7.2 XR开发 183
7.3 XR中的性能增强 187
7.3.1 物尽其用 187
7.3.2 单通道立体渲染和多通道立体渲染 188
7.3.3 应用抗锯齿 190
7.3.4 首选前向渲染 190
7.3.5 VR的图像效果 190
7.3.6 背面剔除 191
7.3.7 空间化音频 191
7.3.8 避免摄像机物理
碰撞 191
7.3.9 避免欧拉角 192
7.3.10 运动约束 192
7.3.11 跟上最新发展 192
7.4 本章小结 193
第8章 掌握内存管理 194
8.1 Mono平台 195
8.1.1 内存域 196
8.1.2. 垃圾回收 198
8.2 代码编译 201
8.2 代码编译 201
8.3 分析内存 204
8.3.1 分析内存消耗 204
8.3.2 分析内存效率 205
8.4 内存管理性能增强 205
8.4.1 垃圾回收策略 205
8.4.2 手动JIT编译 206
8.4.3 值类型和引用类型 207
8.4.4 字符串连接 214
8.4.5 装箱 217
8.4.6 数据布局的重要性 218
8.4.7 Unity API中的数组 219
8.4.8 对字典键使用
InstanceID 220
8.4.9 foreach循环 221
8.4.10 协程 221
8.4.11 闭包 221
8.4.12 .NET库函数 222
8.4.13 临时工作缓冲区 222
8.4.14 对象池 223
8.4.15 预制池 225
8.4.16 IL2CPP优化 239
8.4.17 WebGL优化 239
8.5 本章小结 239
第9章 面向数据的技术栈 240
9.1 多线程的问题 241
9.2 Unity的作业系统 244
9.2.1 一个基本的作业 245
9.2.2 一个较复杂的示例 247
9.3 新的ECS 251
9.4 Burst编译器 258
9.5 本章小结 259
第10章 使用GPU Instancing 优化大量动画对象 260
10.1 应用场景 260
10.2 实现思路 261
10.3 主要实现步骤 261
10.4 部分核心逻辑伪代码 261
10.5 第一个版本——实现 262
10.5.1 运行 262
10.5.2 项目概览 265
10.5.3 编辑器烘焙代码详解 265
10.5.4 运行时代码和Shader详解 274
10.5.5 C#代码详解 281
10.6 第二个版本——优化 282
10.6.1 AnimationInfo 283
10.6.2 GPUInstancing
Animation 283
10.6.3 AnimatorBakeInfo 283
10.6.4 AnimationBaker 284
10.7 本章小结 289
第11章 提示与技巧 290
11.1 编辑器热键提示 291
11.1.1 GameObject 291
11.1.2 Scene窗口 291
11.1.3 数组 292
11.1.4 界面 293
11.1.5 在编辑器内撰写文档 294
11.2 编辑器界面提示 294
11.2.1 脚本执行顺序 294
11.2.2 编辑器文件 294
11.2.3 Inspector 窗口 296
11.2.4 Project窗口 297
11.2.5 Hierarchy窗口 298
11.2.6 Scene和Game窗口 299
11.2.7 Play模式 299
11.3 脚本提示 300
11.3.1 一般情况 300
11.3.2 特性 301
11.3.3 日志 302
11.3.4 有用的链接 302
11.4 自定义编辑器脚本和 菜单提示 302
11.5 外部提示 303
11.6 其他提示 304
11.7 本章小结 305
前 言
用户体验在所有游戏中都是重要的组成部分,它不仅包括游戏的剧情和玩法,也包括运行时画面的流畅性、与多人服务器连接的可靠性、用户输入的响应性,甚至由于移动设备和云下载的流行,它还包括最终程序文件的大小。由于Unity等工具提供了大量有用的开发功能,还允许个人开发者访问,因此游戏开发的门槛已大大降低。然而,由于游戏行业的竞争激烈,玩家对游戏最终品质的期望日益提高,因此就要求游戏的各方面应能经得起玩家和评论家的考验。
性能优化的目标与用户体验密不可分。缺乏优化的游戏会导致低帧率、卡顿、崩溃、输入延迟、过长的加载时间、不一致和令人不舒服的运行时行为、物理引擎的故障,甚至过高的电池消耗(移动设备通常被忽略的指标)。只要遭遇上述问题之一,就是游戏开发者的噩梦,因为即使其他方面都做得很好,评论也会只炮轰做得不好的一个方面。
性能优化的目标之一是最大化地利用可用资源,包括CPU资源,如消耗的CPU循环数、使用的主内存空间大小(称为RAM),也包括GPU资源(GPU有自己的内存空间,称为VRAM),如填充率、内存带宽等。然而,性能优化最重要的目标是确保没有资源会不合时宜地导致性能瓶颈,优先级最高的任务得到优先执行。哪怕很小的、间歇性的停顿或性能方面的延迟都会破坏玩家的体验,打破沉浸感,限制开发人员尝试创建体验的潜力。另一个需要考虑的事项是,节省的资源越多,在游戏中创建的活动便越多,从而产生更有趣、更生动的玩法。
同样重要的是,要决定何时后退一步,停止增强性能。在一个拥有无限时间和资源的世界里,总会有一种方法能让游戏变得更出色、更快、更高效。在开发过程中,必须确定产品达到了可接受的质量水平。如果不这样做,就会重复实现那些很少或没有实际好处的变更,而每个变更都可能引入更多的bug。
判断一个性能问题是否值得修复的最佳方法是回答一个问题:“用户会注意到它吗?”如果这个问题的答案是“不”,那么性能优化就是白费力气。软件开发中有句老话:
过早的优化是万恶之源。
过早优化是指在没有任何必要证据的情况下,为提高性能而重新编写和重构代码。这可能意味着在没有显示存在性能问题的情况下进行更改,或者进行更改的原因是,我们只相信性能问题可能源于某个特定的领域,但没有证据证明的确存在该问题。
当然,Donald Knuth提出的这一常见说法的含义是,编写代码时应该避免更直接、更明显的性能问题。然而,在项目末尾进行真正的性能优化将花费很多时间,而我们应该做好计划,以正确地改善项目,同时避免在未进行验证的情况下实施开销更大和更耗时的变更。这些错误会使整个软件开发团队付出沉重的代价,为没有成效的工作浪费时间是令人沮丧的。
本书介绍在Unity程序中检测和修复性能问题所需的工具、知识和技能,不管这些问题源于何处。这些瓶颈可能出现在CPU、GPU和RAM等硬件组件中,也可能出现在物理、渲染和Unity引擎等软件子系统中。
在每天充斥着高质量新游戏的市场中,优化游戏的性能将使游戏具有更大的成功率,从而增加在市场上脱颖而出的机会。
本书内容
本书适合想要学习优化技术,用新的Unity版本创建高性能游戏的游戏开发者。
第1章探索Unity Profiler,研究剖析程序、检测性能瓶颈以及分析问题根源的一系列方法。
第2章学习Unity项目中C#脚本代码的最佳实践,最小化MonoBehaviour回调的开销,改进对象间的通信等。
第3章探索Unity的动态批处理和静态批处理系统,讨论如何使用它们减轻渲染管线的负担。
第4章介绍艺术资源的底层技术,学习如何通过导入、压缩和编码避免常见的陷阱。
第5章研究Unity内部用于3D和2D游戏的物理引擎的细微差别,以及如何正确地组织物理对象,以提升性能。
第6章深入探讨渲染管线,如何改进在GPU或CPU上遭受渲染瓶颈的应用程序,如何优化光照、阴影、粒子特效等图形效果,如何优化着色器代码,以及一些用于移动设备的特定技术。
第7章关注VR和AR等娱乐媒介,还介绍了一些针对这些平台构建的程序所独有的性能优化技术。
第8章讨论如何检验Unity引擎、Mono框架的内部工作情况,以及这些组件内部如何管理内存,以使程序远离过高的堆分配和运行时的垃圾回收。
第9章研究了多线程密集型游戏的Unity优化——DOTS,介绍了新的C#作业系统、新的Unity ECS和Burst编译器。
第10章讲解了如何将Skinned MeshRenderer转为MeshRenderer,同时启用GPU Instancing优化大量动画对象。本章由译者根据本书内容所编写,对Unity的较新技术做了补充。
第11章介绍Unity专家用于提升项目工作流和场景管理的大量有用技术。
阅读本书的条件
本书主要关注Unity 2019和Unity 2020的特性和增强功能。书中讨论的很多技术可应用到Unity 2018或更旧版本的项目中,但这些版本列出的特性可能会有所不同,这些差异会在适当的地方突出显示。
值得注意的是,书中的代码应该用于Unity 2020,但在撰写本文时,只能在alpha版本上进行测试。额外的不兼容性可能会出现在Unity 2020的非alpha阶段。
下载示例代码文件
本书提供相关代码、参考网站,以及本书中使用的屏幕截图、图表的彩色图像,可以扫描本书封底的二维码下载。
如果代码有更新,在现有的GitHub存储库上也会有更新。
约定
代码块的格式设置如下:
void DoSomethingCompletelyStupid() {
Profiler.BeginSample(“My Profiler Sample”);
List listOfInts = new List();
for(int i = 0; i < 1000000; i) {
listOfInts.Add(i);
}
Profiler.EndSample();
}
读者反馈
欢迎读者提供反馈。
如果你对本书的任何内容有问题,请在电子邮件的主题中提到本书的标题,并发送电子邮件到[email protected]。
评论
还没有评论。