使用 Unity 引擎时有哪些禁忌?

美术和程序两方面描述。
关注者
1,056
被浏览
131,248
登录一下,更多精彩内容等你发现
贡献精彩回答,参与评论互动

前言:最大的禁忌是误认为“Unity入门很简单”。想当程序?C语言基础,数据结构,设计模式,内存管理,编译原理,多线程并发,实时图形学这些不学好还想做程序?你想你horse呢?基础不行的关掉回答吧,这篇回答对你毫无帮助的。基础OK但是引擎可能不熟悉的大佬们请继续往下看。

程序方面:

禁忌1:错误的认为Unity有Terrain这个功能。

Unity没有这个功能,你看到的那个组件是个玩具,要常常这么告诉自己。想做开放世界大地形?成,自己撸Procedural Virtual Texture,自己撸四叉树LOD,流式加载,Terrain Decal……Unity是不会有的,反正我目前就是在自己做这些工作,因为这个组件真是完全不能用。。。团队需要做这一方面,别多想马上拉一支渲染团队自己搞吧,毕竟自己的轮子才是靠谱的。

禁忌2: 使用Resources文件夹。

我的经验告诉我,没什么使用这个文件夹的必要,如果是美术资源或Shader,应该使用ScriptableObject进行全局管理,如果是二进制文件应该直接使用.Net提供的文件读取,这个功能官方都不推荐使用,无论是从实现效率,还是项目管理上来讲,直接用地址去读取项目资源看起来都是一种非常低效的办法。

禁忌3:写代码时搞混FixedUpdate与Update的关系。

其实这个设计本身是一个非常聪明的设计,将物理计算使用一个单独的固定帧时间。假设默认FixedUpdate是20ms一帧,而每帧实际执行时间为10ms,那么FixedUpdate就会每两帧执行一次,如果每帧实际执行时间为40ms,那么FixedUpdate则会每帧执行两次,这样物理引擎就不会出现时钟问题。所以诸如输入输出一类的代码写在FixedUpdate中是错误的,因为有可能触发的时候FixedUpdate完全没有被执行,所以正确的做法是统一管理输入输出,将键盘鼠标的输入以消息方法的形式发送出去,等到执行FixedUpdate时处理消息。这点许多老程序刚刚转到Unity时很容易阴沟里翻皮水,要特别注意。

禁忌4:逻辑都怼主线程。

其实现在Unity的多线程已经放的比较开了,甚至连Transform都有了一个TransformAccess这么个东西,而且多线程计算逻辑在大多数时候都能带来明显的性能提升,毕竟现在四核都算少的,六核八核都快成主流了。不能在分线程访问的一般是一些内置组件的属性值,比如Light.intensity{get;set;},而这种赋值类型的计算其实消耗很小,完全可以把最耗时的计算逻辑放在Job System中计算,大大降低主线程的负担。

禁忌5:粗放式的内存管理。

一般游戏开发中是绝对不允许GC带来的高昂消耗的,动辄几十毫秒的GC时间就是顶配I9处理器也得乖乖的跪下,而高昂的GC消耗实际上99%来自开发者工作的疏忽。譬如unmanaged数据类型可以使用引擎自带的Memory Allocator进行分配,每次new的时候都要想清楚自己这个new是否可以复用,是否会像黄河的河床一样越埋越高,隐患越来越大,最终造成“决堤”,带来不可挽回的毁灭性的损失。如果是UI带来的GC压力,可以考虑魔改UI层源码,通过提交一个字符串的引用而不是强硬的深复制,一般正确的做法是直接调用UnityEngine.Scripting.GarbageCollector关掉自动GC,并在需要的时候手动调用GC,如果在游戏运行过程中内存直接炸掉,这就要准备分锅了,看谁写的代码在不断的制造内存垃圾,引发内存泄露。

禁忌6:Shader中使用大量的multi_compile分支。

multi_compile是一个比较尴尬的设计,是会导致包体体积巨量增大的一个隐患,如果需要做分支功能,建议使用多个Pass等操作,尽可能减少multi_compile的数量。

禁忌7:项目过度封装。

过度封装是一些开发经验不足的团队常出现的问题。过度封装很多时候是开发团队成员之间互相不信任,通过多层保护和限制使项目能work,然而这样会使得项目开发效率和运行效率严重低下。如果老板为了省成本招了一堆工资低水平低的搬砖工,然后指望依赖少数的高手做框架把项目封装死让搬砖工们老实搬砖不出幺蛾子,那么这个项目的下场已经可想而知了,反正高手们到哪都能混的风生水起,如果实在改变不了老板的主意就另作打算吧。。

美术(TA)方面:

禁忌1: 导入模型时有多套UV。

自己在DCC软件中分UV2当然是一种可行的方案,如果自己分光照UV,那么最好直接在软件中制作好光照贴图,并在引擎中将光照贴图打包成一个一整块,比如TexArray,供场景使用。如果不是为了提前烘焙光照则尽量不要在DCC中分UV2。

禁忌2:使用大量SubMesh/SubMaterial。

Drawcall中比较昂贵的部分就在重新绑定材质资源属性上,也就是SetPass Call,同一个物体上有多个材质将会迫使引擎在每次进行多次SetPass Call。如果只有一个材质,那么引擎可能将周围一片使用相同材质统一进行SetPass,绘制效率可以大幅度提高。因此在确保使用了统一的基于物理的着色模型后,可以大幅度降低材质种类和Shader种类,尽可能消灭SubMesh。

禁忌3: 慎用GPU Skinning。

Unity提供的GPU Skinning比较弱,有时候不仅没有优化反而负优化,这是历史遗留问题。如果希望使用GPU Skinning建议使用刚才上方提到的TransformAccess在Job中导出骨骼矩阵数据,并传递到Compute Buffer在Compute Shader中计算,我在文章中讲过这方面的内容:

MaxwellGeng:GPGPU Computing Animation & Skinning?zhuanlan.zhihu.com图标

禁忌4: 模型LOD处理不恰当。

Unity内置的LOD Group组件并不实用,毕竟是一个很古老的组件了。实际开发过程中应该根据需求采用不同的LOD方法,如开放地形的建筑群可以使用HLOD,人物可以使用动态曲面细分,平坦地形和海面可以使用四叉树等……按需分配才是正解。

先说这么多,想到什么再补。

继续浏览内容
亚搏
发现更大的世界
打开
浏览器
继续