在Unity 5中优化SkinnedMeshRenderer
过早优化是万恶之源”——Donald Knuth
不少开发者在前期开发过程中对算法等类似的开销都甚少关心,而是更倾向于尽可能简单的解决某个问题,后面必要时再进行优化。这能极大加速开发进度,并保证代码简洁。但开发后期通常会出现的瓶颈就是图形资源,而优化图形渲染这一块比较有难度。
本文将分享作者Lamebait在使用Unity5制作沙盘游戏过程中优化SkinnedMeshRenderers的相关步骤提供给大家参考。
第一次迭代——使用不带动画的网格
每个城市街区约有15个网格,首先最显著的问题就是不断被加载到游戏中Mesh数量。当街区数量增长到数百之后,DrawCall数量也飙升到大多硬件所不能承受之高。Unity支持网格批处理,能减少一部分DrawCall。但所有网格都是有动画的,所以这些网格用的是SkinnedMeshRenderer组件而非MeshRenderer,Unity不支持对SkinnedMeshRenderer进行批处理。
第二次迭代——SkinnedMeshRenderer.BakeMesh()
所有的建筑和树木都只在它们出现和消失的时候有渐入和渐出的动画,一旦稳定下来之后就是完全静止的了,那可否在此期间将它们变为MeshRenderer呢?
如果使用带有MeshRenderer的无动画网格,通过开关选择使用MeshRenderer还是SkinnedMeshRenderer,结果可能会发现有几个网格与其SkinnedMeshRenderer的最终状态不太匹配,所以这条路不通。
下图展示了SkinnedMeshRenderer的最终状态与静态网格本身的差别。
SkinnedMeshRenderer中有个BakeMesh()函数,功能是按照网格当前的动画状态创建网格数据快照,并输出这个网格数据用于其它地方。这样就可以将输出的新网格传给MeshRenderer然后享受自动批处理的功能。但事情并非如此简单。
下面创建包含各种网格类型的字典,以便多个MeshRenderer可以共享同一个网格,然后让Unity进行批处理。不论何时增加了新的网格,它都会被烘焙出来并加到字典中。但这样会爱导致进行网格类型切换后网格的高度略微有点拉伸。这是因为建筑的缩放值不是0,以致SkinnedMeshRenderer输出的网格本身被缩放了一次,而这个网格在应用到GameObject上的时候由于GameObject本身的缩放值又被缩放了一次。解决这种矛盾的办法就是先将建筑的缩放值设为1,烘焙后再设回原始值。
到此整个切换看起来完全无缝。但这是有代价的,因为Unity也不支持对使用了阴影的MeshRenderer进行批处理。而关闭阴影又会对游戏效果大打折扣,所以必须想想其它办法。
第三次迭代——网格合并
还可以手动批处理,因为网格是可以合并成一张大网格的。当然也有些限制,如网格材质必须相同,单个网格的三角形数量有限等。还好这个游戏的建筑和树木总共才用到了三种不同的材质,所以可以将整个街区合并成最多三张大网格。
基本上,创建CombineInstance后将BakeMesh()输出的网格传给它并加上Transform。最重要的是确保Transform的变换矩阵中GameObject本身的缩放值都是无效的,否则网格会像上文提到那样错误变形。合并后网格的最终结果会应用到网格之前所在的GameObject,然后在街区状态变为静止后移除。
整个过程比较棘手。游戏中很多因素都会导致奇怪的效果,对于每个因素及每个可能的组合都要单独测试。但结果证明这是值得的,现在游戏在有阴影的情况下帧率也非常可观!
合并的红色网格如下图:
第四次迭代——更高一级
这游戏设计的特色之一就是每个阵营最终的街区都会在生成之后被保留,所以如果街区从未改变过,可以将它们合并到一起。一个个合并会遭遇前面提过的网格大小限制。而将城市分为几个格子可以将几个街区的网格合并为单个,从而进一步降低DrawCall。效果如下图:
总结
本文最重要的三点:
- 不要过早优化,可以适当晚一点。
- 善于发现漏洞!如果某个东西不适用于X,那能否暂时将它变为Y呢?
- 用创造性的技巧换取性能。
内容下载链接:
https://github.com/Ryxali/StateCapital
在Unity 5中优化SkinnedMeshRenderer的更多相关文章
- Unity优化方向——优化Unity游戏中的图形渲染(译)
CPU bound:CPU性能边界,是指CPU计算时一直处于占用率很高的情况. GPU bound:GPU性能边界,同样的是指GPU计算时一直处于占用率很高的情况. 原文:https://unity3 ...
- 【Unity优化】如何实现Unity编辑器中的协程
Unity编辑器中何时需要协程 当我们定制Unity编辑器的时候,往往需要启动额外的协程或者线程进行处理.比如当执行一些界面更新的时候,需要大量计算,如果用户在不断修正一个参数,比如从1变化到2,这种 ...
- 【Unity优化】怎样实现Unity编辑器中的协程
Unity编辑器中何时须要协程 当我们定制Unity编辑器的时候,往往须要启动额外的协程或者线程进行处理.比方当运行一些界面更新的时候,须要大量计算,假设用户在不断修正一个參数,比方从1变化到2.这种 ...
- Unity优化方向——优化Unity游戏中的垃圾回收(译)
介绍 当我们的游戏运行时,它使用内存来存储数据.当不再需要该数据时,存储该数据的内存将被释放,以便可以重用.垃圾是用来存储数据但不再使用的内存的术语.垃圾回收是该内存再次可用以进行重用的进程的名称. ...
- Unity 几种优化建议
转: http://user.qzone.qq.com/289422269/blog/1453815561?ptlang=2052 Unity 几种优化建议 最简单的优化建议: 1.PC平台的话保持场 ...
- 通过profiler对unity进行针对性优化
转 : http://user.qzone.qq.com/289422269/blog/1453815629?ptlang=2052 通过profiler对unity进行针对性优化 1. CPU U ...
- i3D的一篇Unity教程中的笔记
原地址:http://blog.sina.com.cn/s/blog_72b936d80100wwej.html 以下是i3D的一篇Unity教程中的笔记. i3D的这篇教程是[i3D.Next-Ge ...
- Unity 绘图性能优化 - Draw Call Batching
Unity 绘图性能优化 - Draw Call Batching Unity官方链接:http://docs.unity3d.com/Manual/DrawCallBatching.html 转载请 ...
- Unity UI性能优化技巧
本文将介绍一些提升Unity UI性能的技巧.更多优化技巧,可以观看Unity工程师Ian Dundore在Unite Europe 2017的演讲<使用Unity性能提升技巧>. 1.划 ...
随机推荐
- zabbix配置邮箱报警功能
1.查看是否安装mailx rpm -qa |grep mailx,本人机器上面已经安装如果没有安装直接用yum安装即可 yum -y install mailx2.vim /etc/mail.rc ...
- shell 脚本中 while 只执行一次
实例代码 while read line ; do ssh -p20002 $line -o StrictHostKeyChecking=no xxxxxxxxx done < ip.txt w ...
- java String 常用方法
String方法 class CeShi{ public static void main(String[] args) { //toCharArray char chararraryone[]=&q ...
- AjAX2 异步通信 异常处理
<!DOCTYPE html> <html lang="en"> <head> <title>xmlhttprequest ajax ...
- css ie bug 双边距
- 【笔试题】python文件操作
请说出下面代码结果及原因,很easy. 说明:test.txt文件不存在 with open('test.txt','w+') as f: f.write('34') f.seek(0) f.writ ...
- MySQL 官方测试库
MySQL 官方测试库 github 地址 https://github.com/datacharmer/test_db MySQL 文档地址 https://dev.mysql.com/doc/em ...
- NOIP 2014 比例简化
洛谷 P2118 比例简化 洛谷传送门 JDOJ 2892: [NOIP2014]比例简化 T2 JDOJ传送门 Description 在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结 ...
- 【Excel】去空格
TRIM(TEXT) 不好用的话,把格式换成
- 链接指示:extren"C"
C++程序有时需要调用其他语言编写的函数,最常见的是调用C语言编写的函数.像所有其他名字一样,其他语言中的函数名字也必须在C++中进行声明,并且该声明必须指定返回类型和形参列表.对于其他语言编写的函数 ...