Unity 项目经验之谈

1、美术篇

·美术规范:主要包括材质数量、模型三角面、纹理尺寸、粒子数量、动画帧频。

a、对于导入unity的模型

 需要注意:若勾选上图中”Read/Write Enabled”将会使该模型在内存中存在一份拷贝,用于在脚本中对模型进行修改。若该模型不会在脚本中进行修改,则不勾选。Optimize Mesh 必须勾选,便于引擎底层对Mesh进行优化处理。Normals & Tangents 中的Normals选项若设置为非Import项,可以降低Memory,并减少ipa/apk包体容量。

b、对于unity贴图

Unity支持目前主流的各种图片格式,包括PSD,TGA,PNG,GIF,BMP,JPG,TIFF,PICT等。若图片尺寸不是2的指数,其所占用内存的大小略大于原始尺寸,并且GPU对其进行读取的速度也有可能会略微偏慢。若勾选Generate Mip Maps,改贴图所占用内存会变大33%,但对整体性能有很大提升。

c、对于光照

移动平台推荐使用Baked或 Mixed,避免使用RealTime模式的光照。Render Mode 不推荐使用Important。使用Baked模式时,在菜单Window->Lighting的Object标签页,可通过设置Scale In Lightmap的值,以变更lightmap中有多少像素值用于该GameObject的光照计算。

d、对于音效

Unity支持主流的各种音乐格式,包括mp3,ogg,wav,aif等。Load Type 中的Decompress On Load 选项不推荐用于大文件。大文件推荐使用 Compressed In Memory选项。Load In Background 如果勾选表示该音频文件将在后台加载,而不会造成主线程阻塞。

2、程序篇

a、逻辑架构

设计时应该遵循各功能模块的独立性和封装性,并满足即插即用。比如,整个游戏逻辑可分为;场景模块,角色模块,UI模块,网络通信模块,战斗模块等。模块化设计不仅游戏逻辑树简单易懂,便于代码审查,而且也有益于项目后期做性能优化以及Bug检查。比如,调试Bug时,如果禁用某一个模块,游戏正常运行,并且Bug不再出现,则Bug由该模块引擎的概率很高。同理,在做优化处理是,如果禁用某一个模块,发现CPU负载下降很多,则该模块造成性能瓶颈的概率也很高。

b、脚本应用

Unity的脚本使用托管机制,如果某脚本需要挂载到场景GameObject上,则该脚本需要继承于MonoBehaviour。在菜单Edit-> Project Settings -> Script Execution下,可更改各类脚本的执行顺序。同时,MonoBehaviour的执行并非使用系统反射机制,而是基于队列存储形式。

为了减少代码托管开销,在设计具体脚本时可以做一些优化处理。比如,有一个类ClassA,继承于MonoBehaviour,在其Update函数里会执行具体逻辑。若该类有30个实例同时存在,则会存在30次托管开销,遇到此类情况,建议删除ClassA中的Update函数,转而由自定义的UpdateEx函数替代。同时,额外编写一个ClassAManager类,其缓存一个ClassA的数组或者队列,每次Update时遍历该队列,执行每个实例的UpdateEx函数。(这个还真没注意,以后要试试)

c、Asset管理

Unity中的Asset序列化支持二进制、文本模式、混合模式三种,具体可以在菜单Editor Settings –> Asset Serialization 下进行设置,文本模式采用YAML格式,增加可读性。其中每一个资源文件都可以生成一个对应的meta文件。(其实至今不知道这个序列化到底有什么好处,有哪位读者大大知道,指点一下小菜鸟吧!!!)

在制作场景时,建议把场景中的具体GameObject制作成Prefab,而不是直接使用FBX格式,这样便于引擎底层做资源管理。

Unity引擎中各种美术资源都可以编译成AssetBundle,包括纹理,模型,Prefab,AnimationClip,AudioClip等。同时,AssetBundle支持压缩与非压缩格式,开发者可根据项目实际情况进行设置。

d、动态更新

通常动态更新包括美术资源与脚本的更新,美术资源建议使用AssetBundle,脚本更新在Android平台上可使用dll反射实现(仅限Anadroid平台),或者通过其它第三方非官方模式。(这部分目前还没接触到,自己做的东西还没用过这个,所以还在学习。。。。)

3、优化篇

a、图形优化 - Graphics

要实现图形优化,首先需要熟悉图形学整个渲染管线流程,在此对其作简要介绍:

应用程序 (Application) -> 几何体 (Geometry) -> 光栅化 (Rasterizer)。

其中,几何体阶段具体包括:模型变换(Model & View Transform) -> 顶点着色(Vertex Shading) -> 投影变换(Projection) -> 裁切(Clipping) -> 屏幕映射(Screen Mapping)。

光栅化阶段包括: 三角设置(Triangle Setup) -> 三角遍历(Triangle Traversal) -> 像素作色(Pixel Shading) - > 合并(Merging)。

进行图形优化时,首要步骤即为定位瓶颈在何处,CPU还是GPU?

如果渲染瓶颈发生在CPU,通常对CPU进行的图形相关优化主要涉及以下几点:

合并模型(美术人员手动合并或者使用引擎的Batching技术)

在合并模型时,如果被合并的模型并未使用同一材质,那么该合并操作并不会提升性能。同理,如果被合并的模型使用了多重材质,而并不共用贴图,合并操作也不会提升性能。

减少材质的使用数量,尽量材质共用

纹理拼接,把多张小尺寸纹理拼接到同一张大尺寸纹理中

避免使用多重渲染,比如反射,阴影,像素光照等

动画优化,包括减少骨骼数量,降低动画帧率等


CPU在图形渲染中所承载的计算量没有GPU那么高(前提是设备同时具备GPU和CPU),所以在进行图形优化时,更多是针对GPU端,其具体包括:

模型对象

调整模型三角面是优化美术资源的基本步骤,如果一个角色模型1500面能达到要求,那为何要使用1600面呢。

当场景中某些对象被标记为Static时,禁止在脚本中对其进行位置,朝向,缩放更改,也就是如果需要更改一个对象的Transform属性值,则改对象不应该被标记为Static。

在设计模型时,尽量减少UV映射缝隙和硬边的数量。

光照设计

在移动设备上,尽量使用light map代替实时光照,即便美术人员需要很炫的光照效果,也可以预先由美术人员调节好实时光照效果后再进行light map烘焙。

在某些特定情况下,美术人员可能需要一些特定对象呈现出酷炫的效果,建议使用Shader实现,而非采用增加额外的光源。

减少像素光的数量(像素光是指的什么?求指点),不仅可以降低CPU负载,也可以减少GPU消耗。如果场景中某像素光照作用的两个模型对象距离相隔较远,建议不要对该模型对象进行合并操作。

Shader性能

Unity引擎为开发者提供了大量的内置Shader,基本满足开发者的项目需求。如果某些特殊效果需要自定义Shader,在编写Shader程序时,需要注意一些具体细节。

在Shader程序中减少使用或者不使用条件语句。GPU在硬件层面上与CPU有着极大差异,GPU以ALU(逻辑运算单元)著称,而CPU则存在着大量的控制器。

定义变量时,应考虑变量需要的精度位宽(Float 为32位,half为16位,fixed为10位),比如定义的变量用于UV坐标,则类型通常选择half即可,如果选择float,则会造成带宽浪费以及计算消耗增加。

避免使用复杂的数学计算函数,比如sin,tan,pow,exp,log等,如果实在需要,建议单个Shader程序里该类复杂函数的使用次数不超过一次。

移动平台避免使用Alpha Test和Alpha Blend指令,如果不可避免,建议使用Alpha Blend,而非Alpha Test。

纹理压缩

压缩纹理不仅可以节省内存,同时也节省运算带宽。同时,建议3D模型贴图都应生成对应的Mipmaps,如果选择生成Mipmaps,则该纹理对应的内存大小相对原先会变大33%左右,但如果不选择生成Mipmaps,则在整体性能上会有很大损失。

LOD使用

Unity中关于LOD的使用有LOD Group和Camera.layerCullDistances两种方式。其中LOD Group主要用于大型模型对象,而Camera.layerCullDistances主要用于碎片化的模型对象。

b、物理优化

Unity引擎中物理计算更新在FixedUpdate中完成,根据具体的游戏项目,如果游戏物理更新频率不需要太高,可以在菜单Project Settings -> Time 下更改Fixed TimeStep的值。

使用物理碰撞体时,在满足设计要求前提下,建议使用Sphere Collider 或者 Box Collider代替Mesh Collider。Mesh Collider和wheel Collider其计算较为复杂,能避免使用则避免之。

被标记为Static的碰撞体,禁止对其移动位置。

如果对象不需要Rigidbody组件,一律删除。

在脚本中如果通过Physics.RaycastAll类似的接口获取固定对象,缓存所得到的对象,禁止通过程序中每帧调用该类接口去获取一个固定的对象。

c、程序优化

程序优化的根本在于设计,在于程序员在编写程序时是否有细心思考。尽管Unity引擎本身由C++编写,但上层逻辑脚本基于Mono体系,内存管理使用GC机制。

GC机制在内存管理存在实时性欠缺,而Mono内存基于内存池,即Mono所申请内存不会得到释放(只有在内存池中内存不够使用时,Mono才会申请新的内存),只会返回内存池。

基于以上机制限制,应禁止频繁申请内存,尽量使用对象池管理对象,比如在Update函数里每帧都new 一个数组或者队列,这样极有可能造成GC还未回收先前的内存,内存池中内存不足,又重复申请新的内存,最终Mono内存池越来越大,这是很多开发者都曾遇到的问题。

在Unity引擎层面,可以通过使用IL2CPP技术,使脚本运行速度更快,同时,也可以在Script Call Optimization中设置忽略异常处理。针对具体脚本中负载瓶颈的定位,建议多使用引擎的Profiler工具。

(ps:对于程序优化这部分,基本不理解,还是基础差。。。。哪位能解释一下,或者提供些相关资料。谢谢)

d、文件优化

如果要降低整体文件大小,首先得知道整个项目中每类资源文件具体大小。在Unity完成相关编译后,选择Console -> Open Editor Log选项,会得到如下图所示的信息:

(ps,然而我在windows下打开log文件并没有所有资源的大小描述。。。。纠正一下,在buliding的时候勾选这几个就可以看见了。)

其包括了具体各类资源的总大小,开发者可按照文件大小建立优化顺序。其中,具体在设计到脚本大小优化时,根据项目组具体情况,可以考虑选择.Net 2.0 Subset,在iOS平台也可使用Stripping方法。同时,建议把Resources文件夹下不曾使用的资源删除,需要使用的资源用AssetBundle代替。Resources文件夹下文件太多会严重影响程序的启动时间。

文章摘自Unity官方微信,如有侵权请联系本人下架。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • 111. [动画系统]如何将其他类型的动画转换成关键帧动画? 动画->点缓存->关键帧 112. [动画]Unit...
    胤醚貔貅阅读 12,521评论 3 90
  • 原文地址 http://www.fx114.net/qa-75-172454.aspx 使用Profiler工具...
    IongX阅读 5,672评论 1 11
  • This article is a record of my journey to learn Game Deve...
    蔡子聪阅读 3,546评论 0 9
  • 这个是我刚刚整理出的Unity面试题,为了帮助大家面试,同时帮助大家更好地复习Unity知识点,如果大家发现有什么...
    编程小火鸡阅读 3,825评论 2 35
  • 梦与想 安静的课上,又到了S老师宣布自习的时间了。还没一会儿,S老师缓缓的向坐在最后一排的T同学走去说道“Is t...
    豆豆豆豆爱吃布丁阅读 368评论 0 0