Unity性能优化

SetPass calls表示在当前摄像机的渲染过程中,Unity切换着色器通道(Shader Pass)来渲染游戏对象的次数。一个着色器(Shader)可以包含多个着色器通道,每个着色器通道可以通过不同的方式来渲染游戏对象。但每次切换着色器通道都会消耗一定的性能,应尽量避免这项数据过大。

大地图的分块加载。场景管理器,子场景管理器,整个大地图是一个数组,里面存着所有的子场景,创建子场景。最多加载四个子场景。

不规则地图的解封处理,美术在开发大地图时的工作流程。

玩家的位置和地图中心点的位置,小于某个值(10),就把地图加载出来,小于某个值(10)卸载。

场景模型优化,CPU,GPU。CPU从内存读取数据(比如模型)发出指令,从RAM内存到显卡的AGP端口。显卡把数据放进显存。显卡的运算单元叫GPU。最后送到显示器。

硬件机理,

优化总体原则,

场景优化:

对始终静止不动的游戏对象使用静态合批技术。

尽量使用同一个材质,以便使用动态合批技术。

使用GPU Instancing技术。

使用遮挡剔除。

进入游戏后的第一个场景要尽量简单,这样可以减少游戏的启动时间。可以先进一个简单的场景,再进行异步加载,之后再进入游戏的主要的场景。

尽量避免Hierarchy窗口的层级结构过深。例如一个物体有很多个子物体,这些子物体又有其它子物体,这些子物体又有其它子物体,继续这样下去就会导致层级结构过深,我们应尽量减少这种情况。

Edit------Project Settings------Quality,可以对不同平台中游戏的品质进行设置。

如果使用了后期处理技术,例如Post Processing等插件,调整屏幕效果的属性,不要使用太绚丽的特效,可以优化性能。

要优化Terrain地形,可以使用Unity资源商店的插件,例如Terrain To Mesh插件可以把地形烘焙成网格。

场景要尽可能简单,尽量多使用预制体,用代码动态创建它们出来,并管理它们。

合批的材质如果想修改,修改共享材质,Render,shareMaterial来保证材质共享状态。

一、静态批处理(房子建筑山)

定点数据和三角形索引(三角形构成)数据。

对于始终静止不动的物体使用静态合批后,CPU会把它们合并为一个批次发送给GPU处理,这样可以减少Draw Call带来的性能消耗,从而提升游戏性能。

要使用静态合批,必须确保Edit------Project Settings------Player------Other Settings------Static Batching是勾选的。

把一个物体设置为静态的方法:

选中该物体,点击在Inspector窗口右上角的Static右方的下拉菜单,选择Batching Static

使用静态合批虽然可以提升游戏性能,但是设置为静态的物体在整个游戏中就不能再运动了,强行使它们运动会出问题。

房屋树木石头

二、动态合批

动态合批默认是由Unity自动完成。可以在Edit------Project Settings------Player------Other Settings------Dynamic Batching查看。默认Dynamic Batching是勾选的,当条件满足时,Unity会自动对使用了相同材质(Material)的物体进行动态合批。如果取消勾选,则不会进行动态合批。

1、Unity不能对包含超过900个顶点属性和225个顶点的网格应用动态批处理 。这是因为网格的动态批处理对每个顶点都有开销。例如,如果你的着色器使用顶点位置、顶点法线和单个UV,那么Unity最多可以批处理225个顶点。然而,如果你的着色器使用顶点位置、顶点法线、UV0、UV1和顶点切线,那么Unity只能批处理180个顶点。

2、如果GameObjects使用不同的材质实例,Unity就不能将它们批处理在一起,即使它们本质上是相同的。唯一的例外是阴影施法者的渲染。

3、带有光贴图的游戏对象有额外的渲染参数。这意味着,如果你想批处理光照贴图的游戏对象,它们必须指向相同的光照贴图位置。

4、Unity不能完全将动态批处理应用于使用多通道着色器的GameObjects。

几乎所有的Unity着色器都支持正向渲染中的多个光源。为了实现这一点,他们为每个光处理一个额外的渲染通道。Unity只批处理第一个渲染通道。它不能批处理额外的逐像素灯光的绘制调用。

遗留延迟渲染路径不支持动态批处理,因为它在两个渲染通道中绘制GameObjects。第一个通道是灯光预通道,第二个通道渲染GameObjects。

其中我们要注意的是,物体必须使用相同的材质,才有可能成功进行动态合批

使用动态合批往往能减少CPU和GPU的开销,提升游戏性能,但同时也会占用一定的内存。

三、GPU Instancing(树木草地石块)

使用GPU Instancing可以在一个Draw Call中同时渲染多个相同或类似的物体,从而减少CPU和GPU的开销。

要启用GPU Instancing,我们可以选中一个材质,然后在Inspector窗口勾选Enable GPU Instancing,这样就可以了。

但是即使勾选了Enable GPU Instancing,也不一定会成功。

要成功使用GPU Instancing进行优化,游戏对象必须同时满足以下条件:

1、使用相同的材质和网格。

2、材质的着色器必须支持GPU Instancing。例如标准着色器和表面着色器就支持GPU Instancing。

3、网格的顶点布局和着色器必须相同。如果网格的顶点布局或着色器不同,那么它们就无法被合并成一个实例。

4、每个实例需要有不同的变换信息(例如位置、旋转、缩放)。虽然多个实例可以使用相同的材质和网格,但是它们必须拥有不同的变换信息才能被正确地实例化并渲染出来。

另外需要注意的是,GPU Instancing与SRP Batcher不兼容。如果项目使用了SRP Batcher,并且配置为优先使用SRP Batcher而不是GPU实例化,启用GPU实例化可能不会生效。SRP Batcher是Unity提供的一种渲染优化技术,它可以将多个网格合并成单个批次进行渲染,从而提高性能。在这种情况下,GPU实例化将被忽略。

使用GPU Instancing往往能减少CPU和GPU的开销,提升游戏性能,但同时也会占用一定的内存。

是否要启用GPU Instancing,要根据自己的项目来定。可以尝试启用,在性能分析器中看看效果如果,如果效果好,再确定启用它。

一般来说,当场景中有大量重复的网格实例时,可以尝试启用GPU Instancing。例如场景中有大量树木、草地、石块等,这些实例具有相同的网格和材质,只是位置、颜色等属性稍有差异,那么启用GPU Instancing或许能够显著提高性能。

四、遮挡剔除

正常情况下,如果一个障碍物A挡住了后面的物体B,虽然我们看不见物体B,但是Unity仍然会消耗性能来渲染这个物体B。这样CPU和GPU就会有一部分性能白白浪费在渲染物体B身上。

如果想在一个障碍物挡住了后面的物体后,不渲染被挡住的物体,则可以使用遮挡剔除。

以一堵墙挡住几个小球 为例,选中这堵 ,在Inspector窗口右上角的Static右侧的下拉菜单处选择Occluder Static ,则这堵墙就是遮挡物。分别选中这些小球,在Inspector窗口右上角的Static右侧的下拉菜单处选择Occludee Static,则这些小球就是被遮挡物。

选中摄像机,要确保它启用了Occlusion Culling属性

创建遮挡区域的方法:

方法1、打开Occlusion Culling窗口。打开方法:Window------Rendering------Occlusion Culling------Bake。打开之后,选择Object选项卡,点击Occlusion Areas,点击Create New右侧的Occlusion Area。

方法2、创建一个空物体,在它身上添加Occlusion Area组件

Occlusion Area组件的Size决定了遮挡剔除区域的范围,它越大,烘焙之后生成的遮挡剔除区域就越大。Center控制遮挡区域中心点的世界坐标。Is View Volume表示是否定义视图体积,只有启用了这个选项,Occlusion Area组件才可能生效。

之后,要让遮挡剔除生效,还要在Occlusion Culling窗口的Bake选项卡中点击右下方的Bake按钮,进行烘焙,遮挡剔除才可能生效。而且以后每次调整完场景的遮挡物、被遮挡物、Occlusion Area组件的范围,都要这样烘焙一次。如果点击旁边的Clear按钮,则会清除之前烘焙的数据。

Portal组件的遮挡范围。每次调整完,或者修改过场景,都要重新烘焙。

五、光照优化

减少光源的数量

摄像机离光源近,启动光源,摄像机离光源远,禁用光源。

烘焙光照

光照Light组件Type设置为Point;

参与烘焙的物体比如墙,地面的static属性设置为Contribute GI,

点击Window===》Redering===》Lighting,点击New Lighting Settings改名MyLightSettings;点击Generate Lighting。烘焙比较慢,最好空闲时间烘焙,中午吃饭或者晚上烘焙。

烘焙之前Batches:26,烘焙之后Batches:16。三角面从4.3K变成3k,顶点从8.1k到6.6k。

光照优化

减少光源。

调节好每个Light组件的属性,平衡视觉效果和游戏性能。

尽量不要用实时光照,而是考虑用烘焙光照或者混合光照,此时可以配合光照探针使用。Lighting窗口可以设置烘焙光照的参数。

减少启用的阴影投射。

根据摄像机距离光源的距离,用脚本来决定是否启用光源和阴影。但是这样就会花费一些性能来计算摄像机到光源的距离。

可以考虑设置光照的阴影。无阴影的性能最好,硬阴影的性能稍差,软阴影的视觉效果最好,但是性能是这三者中最差的。

(备注:光照和阴影最影响项目的性能,其次才是模型网格和贴图。把实时光照改成烘焙光照,可以使游戏性能大幅度增加。)

注意MeshRenderer组件上的属性,默认情况下,Unity 会启用阴影投射和接收、光照探针采样、反射探针采样和运动矢量计算。如果项目不需要这些功能中的一个或多个,请确保关闭它们。2D游戏尤其要注意,往往都不需要它们。

远处的景物,如果确定玩家无法到达,则可以不用模型,而是把远处的景物做成一张贴图放到天空盒的材质中,给天空盒使用。也可以使用反射探针烘焙出一张贴图,然后放到天空盒的材质。

六、图片的优化

导入图片之前的优化:

如果这张图片是应用在移动端的,则导入Unity前,可以对这张图的每条边进行调整,确保每条边的长度都是2的正整数次方个像素。例如2、4、8、16...256、512、1024、2048、4096...。这个做法只对移动端有效。

图片导入Unity后,可以选中这张图片,在Inspector窗口设置它的属性。设置这些属性,可以在发布不同的平台,分别对该图片进行相应的压缩。可以在合理的范围内减小Max Size,对于许多移动端的游戏,2048x2048 或 1024x1024 足以满足纹理图集 的要求,而 512x512 足以满足应用于3D模型的纹理的要求 。如果图片不需要读写,则可以取消勾选Read/Write Enabled ,如果勾选可能导致双倍的内存占用。Filter Mode一般选择Bilinear 即可平衡性能和视觉效果,如果选择Point(no filter),则视觉效果不太行,但性能开销也小,如果选择Trilinera,则视觉效果最好,但性能开销最大。Aniso Level一般选择1 ,只有个别比较重要的图片才需要设置为大于等于2的值。

图片导入Unity后,会默认生成Mip Maps 格式。当摄像机到这幅贴图距离近,则显示最原始的图片,当摄像机距离这幅贴图的距离远,则这幅贴图会变模糊 ,以此降低渲染的性能消耗。但由于之前显示的一幅图,现在变成了有多幅,所以这样会略微增加内存消耗。如果确定本游戏的摄像机到图片的距离几乎不怎么变化,则可以禁用这个功能点击该贴图,在Inspector面板的Advanced中取消勾选Generate Mip Maps,这样就不会生成Mip Maps,增加游戏性能。如果是2D游戏则可以禁用这个功能。如果是UI贴图,也可以禁用这个功能。

图片导入Unity后,可以选中这张图片,在Inspector窗口设置它在各个平台的Format和Compressor Quality。

Format可以参考官方文档:https://docs.unity3d.com/2021.3/Documentation/Manual/class-TextureImporterOverride.html

七、UI的优化

如果一个UGUI的控件不需要进行射线检测,则可以取消勾选Raycast Target

尽量避免使用完全透明的图片和UI控件。因为**即使完全透明,我们看不见它,但它仍然会产生一定的性能开销。**如果UI中一定要用到很多张完全透明的图片,则建议把这些完全透明的图片由单独的摄像机进行渲染,且这些UI不要叠加到场景摄像机的渲染范围内。

尽量避免UI控件的重叠。如果多个UI有重叠的部分,则会稍微增加一些额外的计算和渲染的开销。虽然这部分开销通常是非常小的,但我们最好也尽量避免这种情况。

UI的文字使用TextMeshPro比使用Text的性能更好 。但是TextMeshPro对中文的支持不太好。尽量避免UI控件的重叠 。如果多个UI有重叠的部分,则会稍微增加一些额外的计算和渲染的开销。虽然这部分开销通常是非常小的,但我们最好也尽量避免这种情况。

UI的文字使用TextMeshPro比使用Text的性能更好。但是TextMeshPro对中文的支持不太好。

八、模型优化

模型导入Unity后,可以选中这个模型,在Inspector窗口设置它的属性。在Model选项卡,启用Mesh Compression可以压缩模型 ,压缩程度越高,模型精度越低,但是模型也会节省一些空间。如果该模型不需要用代码来读写,则可以取消勾选Read/Write Enabled。设置Optimize Game Objects可以优化模型。如果该模型不需要使用法线,则可以把Normals设置为None。如果该模型不需要用混合变形法线,则可以把Blend Shape Normals设置为None。如果该模型不需要使用切线,则可以把Tangents设置为None。如果该模型不需要用光照UV贴图,则可以取消勾选Swap UVs和Generate Lightmap UVs。

对于Rig选项卡,Animation Type如果选择Generic Rig会比Humanoid Rig性能更好,但是一般使用Humanoid Rig是为了对人型的角色进行动画重定向 ,所以要根据自己的情况来选择。如果模型不需要使用动画,例如一些完全不会动的石头等物体,则可以将Animation Type选择为None。Skin Weights默认是4,对于一些不重要的动画对象,本变量可以设置为1, 这样可以节省计算量。**建议勾选Optimize Bones,这样会自动剔除没有蒙皮顶点的骨骼。**勾选Optimize Game Object可以提高角色动画的性能,但是在某些情况下可能会导致角色动画出现问题,是否勾选要看动画效果而定。如果角色模型是可以换装的,则在导入该模型后不要勾选这个选项,而可以在游戏运行时,该角色换装后,通过AnimatorUtility.OptimizeTransformHierarchy来勾选这个选项。

对于Animation选项卡,如果模型不需要使用动画,则可以取消勾选Import Animation 。对于Animation选项卡,设置Anim.Compression可以调整动画的压缩方式,Off表示不压缩动画,这样动画文件可能会占用较大的空间,但是在运行时不会有任何信息损失,Keyframe Reduction表示使用关键帧算法来压缩动画,这样会显著减小动画文件的大小,同时保持相对较高的动画质量,Optimal表示会尽可能高地压缩网格,但是这样也会导致压缩时间增加。

对于Materials选项卡,如果使用Untiy的默认材质,则可以把Material Creation Mode设置为None。

Edit------Project Settings------Player------勾选Optimize Mesh Data,这样一来,Unity会在构建的时候中对网格数据进行优化处理,以达到提高游戏性能的效果。但是这样往往会修改网格,我们勾选之后应该要进行测试,确保没有问题,再确定启用它。

用LOD技术,使用Unity自带的LOD Group组件,并根据项目的情况来调整该组件的属性。Untiy资源商店也有一些其它的LOD插件。

把多个模型的网格合并为一个网格。可以使用自己写代码,使用Unity自带的CombineMeshes方法,也可以使用资源商店的插件,在资源商店搜Mesh Combine可以搜索到相关的插件,例如Easy Mesh Combine Tool等插件。

减少模型的顶点、面、材质、骨骼、蒙皮网格。这一般由美术人员来完成。

九、LOD Group

LOD的原理,就是我们可以为一个游戏对象设定多个模型,这些模型消耗的游戏性能由高到低排列。会根据摄像机距离模型的远近自动显示对应的模型。

近的时候显示最精细的模型,距离中等的时候显示没那么精细的模型,远的时候显示粗糙的模型,最远的时候可以隐藏该模型。

使用LOD技术能起到优化渲染性能的效果。但是使用LOD技术也会增加内存占用。

在Unity中可以使用LODGroup组件来实现LOD技术

LOD级别LOD 0、LOD 1、LOD 2分别表示摄像机从近处看、从中等距离处看、从远处看时,所使用的模型的信息。Culled表示不渲染该模型。

点开下方的LOD 0、LOD 1、LOD 2,点击+号可以添加在这种情况下要显示的模型。

把LODGroup组件添加在一个空物体身上。这个空物体身上不添加MeshRenderer组件,也不添加MeshFilter组件,但可以添加碰撞器。如果要添加刚体、脚本等,也可以添加到这个空物体身上的。

这个空物体要渲染的每一个模型都要作为它的子物体,它们的身上要添加MeshRenderer组件和MeshFilter组件,用于渲染这个模型,但是不要给它们添加碰撞器。

在该空物体的LODGroup组件中,点击选中要设置的LOD级别,在Renderers下方点击Add可以选择要显示的游戏对象,点击-号可以移除该游戏对象。

Edit------Project Settings------Quality中有控制整个项目LOD的参数。

LOD Bias的值小,则摄像机离物体的距离稍微有些变化,则不同的LOD级别就会切换。如果LOD Bias的值大,则摄像机需要与物体有比较大的距离变化,不同的LOD级别才会切换。

十、合并网格

合并网格就是把多个网格合并为一个整体,从而提升游戏性能。

但是这样一来,我们就不能单独控制这些网格运动了,只能控制合并后的整个网格运动。而且合并的网格使用的材质必须是相同的,合并才可能成功,否则合并之后依然不能提升性能。

可以在Unity资源商店搜Mesh Combine,下载相应的插件来实现合并网格的功能,例如Easy Mesh Combine Tool等插件。

Easy Mesh Comline Tool插件,Package Manager。从资源商店导入插件。

Window===》Easy Mesh Combine Tool 打开之后点击Make Group and

Combile。

十一、动画优化

设置Animator组件 的Culling Mode。Always Animate表示如果该动画不可见,也会播放它。Cull Update Transformations表示如果该动画不可见 ,则不会渲染该动画,但是依然会根据该动画的播放来改变游戏对象的位置、旋转、缩放,这样是常用的选项。Cull Completely表示完全不会播放该动画,不但不会渲染该动画,而且也不会改变游戏对象的位置、旋转、缩放。

禁用SkinMesh Renderer 组件的Update When Offscreen可以让角色在不可见的时候动画不更新,这样可以减少计算量,提升性能。

对于Animator组件,可以使用Animator.StringToHash方法获得指定字符串的哈希值,再把它作为参数传入Animator型对象.GetXXX方法和Animator型对象.SetXXX方法中进行使用。

int hash = Animator.StringToHash("Jumping");

animator.SetBool(hash,true);

不用的Animation组件和Animator组件可以考虑删掉,因为只要它们存在,就会消耗性能来检测当前的状态和过渡条件。

一些简单的动画可以使用DoTween、iTween等插件实现,而不需要每个动画都用Animator来实现。

十二、音频优化

Unity支持后缀为.wav、.ogg、.mp3的音频文件,但建议使用.wav,因为Unity对它的支持特别好。注意:Unity在构建项目时总是会自动重新压缩音频文件,因此无需刻意提前压缩一个音频文件再导入Unity,因为这样只会降低该音频文件最终的质量。

把音频文件导入Unity后,选中它,可以在Inspector窗口设置它的属性。勾选Force To Mono ,这样就会把这个音频文件设置为单声道。可以节省该资源所占据的空间。因为很少有移动设备实际配备立体声扬声器。在移动平台项目中,将导入的音频剪辑强制设置为单声道会使其内存消耗减半。此设置也适用于没有立体声效果的任何音频,例如大多数UI声音效果。

对于Load Type选项,小文件(小于200kb)选择Decompress on Load,中等大小的文件(大于等于200kb)选择Compressed In Memory,比较大的文件(如背景音乐)选择Streaming。

对于Compression Format的选项 ,PCM表示不压缩,Vorbis表示压缩 ,但也会尽量保证音频的质量,ADPCM表示压缩,且压缩的程度比Vobis更高。由于PCM不会压缩音频,所以占用的空间大,应尽量少用,长时间的音频文件可以使用Vorbis,短时间的音频文件可以使用ADPCM。

Sample Rate Setting用于控制音频文件的采样率 ,对于移动平台,采样率不需要太高,建议选择Override Sample Rate,然后在下方的Sample Rate选择22050Hz,一般这样就够用了。

十三、物理优化

使用简单的碰撞器进行碰撞检测,如球体碰撞器、盒子碰撞器、胶囊体碰撞器,少用网格碰撞器 等复杂的碰撞器。即使用多个简单的碰撞器组合在一起,也往往比使用网格碰撞器的性能要好。

如果要把多个碰撞器组合成一个碰撞器,可以用复合碰撞器。

如果同一个功能既可以用碰撞器来做,也可以用触发器来做,则往往使用触发器来做,性能更好。

尽量减少刚体组件,因为刚体组件的物理计算较多。

如果勾选刚体组件的Is Kinematic,则性能会有所提高。但这样一来,这个刚体只会给别的刚体施加力,自己不会受到别的刚体施加的力的作用。

Edit------Project Settings------Player------勾选Optimization下方的Prebake Collision Meshes,可以提高碰撞的效率,但是构建游戏的时间会增长

Edit------Project Settings------Physics或者Physics 2D------设置Layer Collision Matrix 。它规定了哪些Layer层的游戏对象可以彼此碰撞,哪些Layer层的游戏对象会忽略碰撞。如果有些Layer层的游戏对象之前不需要进行碰撞,则可以在这里设置,取消勾选则表示不会碰撞。

Edit------Project Settings------Time------稍微调大Fixed Timestep,这样可以稍微提升游戏性能,但是物体的运动可能会出现问题。

十四、代码优化

代码优化:

使用AssetBundle作为资源加载方案。而且经常一起使用的资源可以打在同一个AssetBundle包中。尽量避免同一个资源被打包进多个AB包中。压缩方式尽量使用LZ4,少用或不要用LZMA的压缩方式。

如果确定后续开发不会升级Unity版本,则可以尝试启用打包选项BuildAssetBundleOption.DisableWriteType,这样TypeTree信息不会被打到AB包中 ,可以极大减小包体大小以及运行加载时的内存开销。

使用AssetBundle或者Addressables加载的资源,如果不使用,要记得卸载它们 ,否则会造成内存泄漏。

不用的资源要释放掉,不用的引用类型的变量也要赋值为null不要让它们一直占着内存中。
加载资源时尽量使用异步加载。

频繁创建和销毁对象,可以使用对象池。

切换场景时 ,旧的场景要释放掉,不用的资源也可以考虑释放掉,也可以考虑用System.GC.Collect来进行一次垃圾回收

锁定游戏的帧率 。帧率为30,游戏会明显卡顿,但是对于手游来说,消耗手机的电量比较少。帧率为45,游戏有一点点卡,但还凑合,消耗电量中等。帧率为60,游戏很流畅,但消耗手机的电量会比较多。可以用Application.targetFrameRate来锁定帧率 ,也可以用UnityEngine.Rendering命名空间中的OnDemandRendering.renderFrameInterval来锁定帧率。

尽量少用foreach语句,可以改为for语句。因为每次使用foreach语句会造成微量的内存垃圾。

要判断GameObject型对象.tag是不是某个标签,使用GameObject型对象.CompareTag方法会更高效

尽量少用GameObject.Find方法和Object.FindObjectOfType方法来查找游戏对象 ,可以提前把要查找的游戏对象存储在变量、列表、字典等容器中,方便查找。也可以用GameObject.FindGameObjectWithTag方法来查找游戏对象。

在UI显示字符串的时候,如果一些内容是固定的,我们可以把它拆分开来,这样可以减少使用+号来拼接的次数,减少内存垃圾的产生。例如"杀敌数:999",其中"杀敌数:"是固定的,冒号后面的数字才是会变的,那么我们可以用两个Text组件分别记录它们,改变的时候只改变冒号后面的数字。

频繁对字符串赋新的值,或者频繁拼接字符串的时候,可以使用StringBuilder代替string

如果要频繁操作某脚本,不要每次都用GetComponent方法来获取这些脚本。可以用一个变量存储起获得的这个脚本,之后要访问它,就直接访问这个变量即可。也可以考虑在生命周期方法Awake或者Start中声明变量来存储,之后访问这个变量即可。

尽量少用正则表达式。虽然正则表达式的形式看上去比较简便,但是使用它会造成一定的性能消耗,且会产生内存垃圾。

尽量少用LINQ语法,因为每次使用LINQ都会产生一定量的内存垃圾。

尽量少用Camera.main来访问主摄像机 ,因为每次访问它,实际上Unity都是从场景中查找它的。可以声明一个变量存储它,在生命周期方法Awake或Start中获取主摄像机的应用。

Animator、Shader中使用Get方法和Set方法时,不传入字符串作为参数 ,而是传入哈希值 。例如Animator组件可以使用Animator.StringToHash方法获得指定字符串的哈希值 ,再把它作为参数传入Animator组件的Get方法或Set方法中进行使用。例如Shader,则可以用Shader.PropertyToID方法来获取指定属性的ID

使用非分配物理API。例如使用Physics.RaycastNonAlloc方法代替Physics.RaycastAll方法 ,使用Physics.SphereCastNonAlloc方法代替Physics.SphereCastAll方法,以此类推。Physics2D类也有类似的方法。

一般情况下,整数的数学运算比浮点数的数学运算效率高 ,浮点数的数学运算比矢量的数学运算效率高。可以灵活运用数学的加法交换律、加法结合律、乘法交换律、乘法结合律,在保证结果不变的前提下,调整运算顺序,减少浮点数的数学运算和矢量的数学运算

使用高效的算法进行计算

每次执行Debug.Log来打印信息会消耗极少量的性能,如果要在游戏正式发布之后不执行某些Debug.Log的语句,但又不想把这些代码删掉,则可以使用宏来禁止在游戏正式发布之后执行Deubg.Log的语句。例如使用#if语句或者Conditional特性。

尽量减少在生命周期方法Update、FixedUpdate、LateUpdate中的逻辑。其中有些不需要频繁执行的逻辑,可以使用协程或者Invoke方法 ,每隔指定的秒数执行一次或每隔指定的帧数执行一次。

尽量避免频繁的装箱拆箱操作。也可以使用泛型,这样就能避免装箱拆箱。但是要注意,Lua热更新对泛型的支持不太好。

如果物体身上添加了刚体组件,则尽量用刚体组件的方法来移动它,而不是用Transform类的方法来移动它。

如果物体身上添加了CharacterController组件,则尽量用CharacterController组件的方法来移动它,而不是用Transform类的方法来移动它。同理,如果物体身上添加了刚体组件,则应尽量用刚体组件的方法来移动它,而不是用Transform类的方法来移动它。

应尽量避免DontDestroyOnLoad中加载的资源过多,因为它在切换场景的时候不会被释放,声明的变量以及加载的资源会一直占用着内存。我们可以考虑把一些资源不用的资源释放掉,需要的时候再加载它。

不使用组件可以删掉,这样可以节省一些内存。常见的有AudioSource组件、Animator组件、Animation组件等,如果它们不需要使用,则可以删掉。

写一个类继承AssetPostProcessor,然后定义里面特定的方法,以此来自动设置资源导入Unity之后的属性。

尽量避免闭包。因为闭包会产生额外的内存开销。

Shader优化:

修改Shader的代码,或者自定义一个Shader

修改渲染管线的源码,改成符合自己项目的渲染管线,或者自定义渲染管线。

相关推荐
在路上看风景3 分钟前
13. UGUI合批
unity
jtymyxmz13 小时前
《Unity Shader》12.2调整屏幕的亮度、饱和度和对比度
unity·游戏引擎
AllBlue21 小时前
unity嵌入安卓界面,如何显示状态
android·unity·游戏引擎
tealcwu1 天前
【Unity技巧】实现在Play时自动保存当前场景
java·unity·游戏引擎
tealcwu1 天前
【Unity基础】实现Scroll View跟随动态内容滚动
java·unity·游戏引擎
野奔在山外的猫1 天前
【文档】VSCode 配置 Unity 环境流程
unity
技术小甜甜1 天前
[Godot排错] 上传 Google Play Console 封闭测试时签名证书不匹配错误的解决方案
游戏引擎·godot·游戏开发
变身缎带1 天前
Unity中的NetworkManager基于protobuf, Socket-TCP
tcp/ip·unity·游戏引擎
AllBlue2 天前
unity调用安卓方法
android·unity·游戏引擎
郝学胜-神的一滴2 天前
Horse3D游戏引擎研发笔记(十):在QtOpenGL环境下,视图矩阵与投影矩阵(摄像机)带你正式进入三维世界
c++·3d·unity·游戏引擎·godot·图形渲染·unreal engine