unity3d物体优化

2018-03-02 23:05:41 Crayon_Chen 阅读数 1079
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

本文是根据泰课视频《Unity3D开发技术讲解》的部分学习整理。

静态优化

  • 静态物体勾选static
  • 贴图处理(属性设置)
    • TextureType选择Advanced
    • 移动设备下设置贴图压缩格式
      • Android原生支持ETC,OPNEGL2.0都支持。ETC2只有OPENGL3.0支持;
      • IOS只支持PVRTC的压缩格式
    • Generate Mip Maps:根据我们的视距采用不同的贴图,小图不勾选。
  • 模型处理
    • 顶点数量越少越好,控制面片数
    • 静态模型删除无效的Animator(从3DMax、Maya导出可能附带多余的Animator)

动态优化

此动态优化针对一些类似游戏内的动态装饰品对象。代码动态实例化的对象不适用此方法!

对于成批的相同物件、骨骼一致、材质一致的对象,组合渲染,减少Draw Call。

新建空对象作为父节点,统一管理成批物件。空对象添加脚本CombineOpMesh.cs

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// 动态优化Unity:组合渲染,减少Draw Call
/// </summary>
public class CombineOpMesh : MonoBehaviour
{
    void Start()
    {
        CombineToMesh(gameObject);
    }

    public void CombineToMesh(GameObject _go)
    {
        SkinnedMeshRenderer[] smr = _go.GetComponentsInChildren<SkinnedMeshRenderer>();
        List<CombineInstance> Icom = new List<CombineInstance>();

        List<Material> Imat = new List<Material>();
        List<Transform> Itra = new List<Transform>();

        for (int i = 0; i < smr.Length; i++)
        {
            Imat.AddRange(smr[i].materials);
            Itra.AddRange(smr[i].bones);

            for (int sub = 0; sub < smr[i].sharedMesh.subMeshCount; sub++)
            {
                CombineInstance ci = new CombineInstance();
                ci.mesh = smr[i].sharedMesh;
                ci.subMeshIndex = sub;
                Icom.Add(ci);
            }
            Destroy(smr[i].gameObject);
        }

        SkinnedMeshRenderer _r = _go.GetComponent<SkinnedMeshRenderer>();
        if (_r == null)
            _r = _go.AddComponent<SkinnedMeshRenderer>();

        _r.sharedMesh = new Mesh();
        _r.bones = Itra.ToArray();
        _r.materials = new Material[] { Imat[0] };
        _r.rootBone = _go.transform;
        _r.sharedMesh.CombineMeshes(Icom.ToArray(), true, false);
    }
}
2017-04-03 14:49:17 BoBoWang1991 阅读数 3475
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

浅谈Unity3D项目优化
作为一个入行不足三年的攻城狮来讲,讲引擎中的优化,经验确实不足,unity3D引擎作为一款侧重移动端游戏开发引擎来讲,优化游戏是确实有必要的,毕竟他要适配所有机型的前提下又要保证游戏画面的清晰度,特效的绚丽多彩,所以国内大部分游戏公司都要喜欢招收既会码代码又会做优化的复合人才。
废话不多说,直接上方案。
性能优化
1.CPU优化
CPU优化

1.DrawCalls
新版Unity也可以叫DrawCall,定义:Unity每次在准备数据并通知GPU渲染的过程称为一次DrawCall,显示在工程中就是Batches的大小,Batches越大,画面越是卡顿,不流畅。Batches即是DrawCall的大小
通常来说,如果是在pc端发布的游戏,DrawCall应该控制在2000以内,如果是要发布到移动端,那么DrawCall最大不能超过300,越低越好,当然在保证画面质量的前提下。那么如何降低DrawCall呢,我在这里说两种最常用的方法,第一种:静态批处理Batching Static,批处理相同材静态独享或者相同纹理的静态对象,直接上图。
把所有静态对象全部设置为BatchingStatic
2.动态批处理
即是批处理非静态对象,但是要求苛刻,稍作修改就会批处理不成功,我建议大家使用静态批处理
动态批处理
物理组件
1.设置一个合适的FixedTimestep.
FixedTimestep
Editor-ProjectSetting-Time,打开可以根据需求动态设置。
2.不要使用MeshCollder,从优化角度来看,尽量减少物理组件的使用。
MeshCollider顾名思义,即是网格碰撞器,如果非要使用,建议大家使用Meshbaker网格合并,合并碰撞器,这一点我设计的有些少发一个链接,大家可以参考一下。http://blog.csdn.net/akof1314/article/details/41347079
3.GC(Garbage Collection垃圾回收)
处理器-调度->GC回收垃圾。
在我们做需要大量生成和销毁游戏对象的游戏时,如FPS类游戏,如果频繁实例化Instantiate和Destroy,则会大量调度GC,从而严重消耗CPU性能,在这里,我就可以使用对象池模式来减少GC的调度,何为对象池呢,对象池就是存放需要被反复调用资源的一个空间,当一个对象会大量生成的时候,如果每次都销毁创建,会非常浪费时间,通过对象池把暂时不用的对象放到一个池子中(也就是一个集合中),当下次要重新生成这个对象的时候,先去池子中查找一下是否有可用的对象,如果有就直接拿出来使用,如果没有,就重新创建,利用空间换时间来达到游戏的告诉运行,减少GC的调度。大家可以参考我对象池的链接,学习一下。
链接http://blog.csdn.net/bobowang1991/article/details/68961877
另外降低GC的方案如下,1减少New产生对象的次数,2,使用公共的对象(静态成员),3.将String换成StringBundle.都可以减少GC的调度,4尽量不用foreach,而是用for,foreach会涉及到迭代器的使用,每一次循环所产生的迭代器会带来24bytes的垃圾,循环10次,就是240bytes。5.不要直接访问gameobject的tag属性,访问物体的tag属性会在堆上额外的分配空间。6.LinQ->连接数据库。
代码质量
1.不要频繁的使用GetComponent,尤其在循环中。
2.善于使用OnBecameVisible()he1OnBecameInVisible().
3.使用内建的数组,如Vecter.Zero而不是new Vector3(0,0,0).
4.善于使用ref关键字
5.将经常需要使用的属性查询缓存起来。
6.不要频繁使用Instantiate和Destroy,使用对象池。
7.习惯性的将暂时不用的GameObject设置为非激活,即使把如图所示
GPU的优化
两种方案:1.减少绘制的数目,2.优化显存带宽。
如何减少绘制的数目
1.保持材质的数目尽可能少,这使得unity更容易进行批处理。
2.使用纹理图像,来代替一些列单独的小贴图。
3.如使用了纹理图像和共享材质,使用Render.SharedMaterial代替Render.material。
4.使用光照纹理,Lightmap,而非实时灯光,这一点尤为重要,但是操作起来不难,我在这里着重讲解。
首先,如果是一个加了大量的灯光和粒子特效,即使是一个小小的塔防游戏,DrawCall也会达到5000以上甚至更高,这是为什么呢,是因为灯光和粒子特效需要GPU实时渲染,灯光和粒子特效的数量越多,DrawCall也就越高。但是我们场景中的灯光是不需要实时渲染的,如果你场景中的灯光很多时,就只需要下面的操作就可以大大降低DrawCall,优化GPU。
首先打开unity中的Windows面板-Light-选择Lights,然后把Baking选择为Baked类型,右下角Auto勾去掉,选择Build等待烘焙完毕即可,如下图所示
下面正在烘焙
大家需要实际操作一下,当然需要实时渲染的灯光不要要烘焙,问题不大。
5.使用LOD,LOD即是远的看不清的物体的细节忽略,当靠近他时才让渲染他的细节,说白了就是物体在远处时,虽然我们的肉眼看不清,但是相机还是在渲染他的所有细节,这是不需要的,此时我们可以使用LOD,把精细的模型换成粗模,一次来减少GPU的渲染,具体操作如下图所示。
LOD Group
添加细模型
6.遮挡剔除。
1.当场景中包含大量模型时,造成渲染效率的降低(即帧速率FPS的降低),采用遮挡剔除技术,可以使得那些被阻挡的物体不被渲染提高渲染效率
2.原理:在场景空间中创建一个遮挡区域,该遮挡区域是有单元格(Cell)组成;每个单元格是构成整个场景遮挡区域的一部分,这些单元格会把整个场景拆分成多个部分,当摄像机能够看到该单元格时,表示该单元格的物体会被渲染出来,其他的不去渲染
3.遮挡剔除步骤:
(1)场景
(2)除了主角,摄像机,直线光,地面。把层级视图中的所有游戏对象标记为“遮挡静态”(Occluder Static/Occludee Static)
(3)执行菜单命令“Windows”—>“Occlusion Culling”,弹出“遮挡剔除”面板,单击下方的“Back”按钮,开始烘焙
(4)单击“遮挡剔除”(Occlusion)窗口的“Visualizatior”,运行程序
4.若场景中存在大量的小“物件”,使用“层消隐距离”来优化场景
(1):原理:较远距离将小物件剔除,减少绘图调用的数量
(2):方法:将小物件放入一个单独的层(Separate Layer)中,并使用Camera.main.layerCullDistances函数设置层的消隐距离
(3)例如:void Start(){
Float[] distances=new float[32];
//这里定义的数组下标“8”表明第8层
distances[8]=10;
Camera.main.layerCullDistances=distances;
}
当摄像机距离这些小物件超过10m的时候,就不可见了
7.使用mobile版的shader。
具体操作入下,新建一个mateiral,inspector-Shader-Mobile-选择需要的类型,适合移动端的发布,pc端也可以使用,包括天空盒也可以使用。
选择mobile版的shader类型
优化显存带宽
1.OpenGL ES 2.0使用ETC1格式压缩等等,在打包设置哪里都有这些选项,点击选择即可。
2.MipMap技术
MipMap是把图片处理成预先计算好的比较小的图集,在在屏幕尺寸变小时调用处理好的小图,以此来节约GPU渲染,但是缺点是会增加33%的图集内存,因为原图还要保存。
MipMapMipMap图面处理效果图
Unity3D内部的优化
1.Resources 资源不用的要删除,纹理,网格,音频,组件等等。
2.在CPU压力不是很大的时候,重置GameObject,组件等占用的内存。
3.在打AssetBundle的时候,可以考虑bundle的压缩等等。
以上为本人近两年工作中所用到的所有优化技术方案,希望对大家有所帮助,谢谢。

2017-03-28 22:18:16 jxw167 阅读数 2607
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

最近给读者分享一下关于Unity3D的优化,这个问题对于开发者来说都是比较头疼的问题,这里先介绍一下关于项目开发通常的做法。开发项目前期由于赶进度,不停的堆积功能和资源,这样项目完成后,包体非常庞大,代码写的也很乱,后期项目进入优化阶段,包括代码的重构,各种BUG的修复,从而导致版本开始变的不可控制,项目研发周期也是不停的延期延期,这种情况在大部分公司都是常见的问题。其实作为老板来说,他肯定要着急看到项目成果,所以就不停的督促开发人员加班加点的搞,站在老板的角度考虑问题,情有可原。

但是,作为开发者来说,我们不能按照老板的节奏走,这样后面不仅坑的是自己,也把公司坑掉了,后期项目由于各种问题很容易夭折,这种局面是不可控制的,因为项目开发完成了,后期还会加入很多功能,如果前期没有规划好,就会出现前一发而动全身的情况,这样也预示着项目即将死掉。如何避免这种情况发生,在这些系列文章中给读者分享一下笔者关于这些问题的解决方案。

用Unity引擎开发,我们就要了解它们的工作机制,这样在项目进行优化时也会有针对性,关于优化方面,笔者也做过一些视频讲座,当然这些系列文章是视频中没有的,Unity首先遇到的问题就是效率问题,很多项目由于效率问题夭折了,所以这个问题的解决非常重要,如何优化效率也就是运行帧率,针对于Unity就是减少Draw Call的数量。

 网上关于Draw Call的介绍非常多,这里再给读者向细的方向讲一下,其实Draw Call的执行就是CPU与GPU之间的通信,这就涉及到渲染流水线的概念,渲染流水线的起点是CPU,主要分三个阶段:

1、CPU把数据加载到显存中

2、设置渲染状态

3、调用Draw Call

根据上面提到的三个步骤,再详细介绍一下,所有游戏中渲染所需要的数据都需要从硬盘中加载到内存中,然后网格和纹理等数据被加载到显卡上的存储空间也就是我们所说的显存。这是因为显卡对于显存的访问速度更快,效果如下:

实际项目开发中,真实渲染中需要加载到显存中的数据比图中显示的更复杂,举例说明一下:顶点的位置信息、法线方向、顶点颜色、纹理坐标等等。

当把数据加载到显存后,在内存中的数据部分可以移除,因为对于一些数据来说,CPU仍然要访问它们,从硬盘加载到内存的过程是十分耗时的,这个也要考虑的。在这之后,开发者还需要通过CPU来设置渲染状态,从而“指导”GPU如何进行渲染工作。

接下来介绍设置渲染状态了,渲染状态定义了场景中的网格是如何被渲染的,如果我们编程没有更改渲染状态,所有的网格都将使用同一种渲染状态。如下图所示效果演示:


以上图片只是表达这个意思,同样的渲染状态,材质是一样的。准备好上述工作后,CPU就需要调用一个渲染命令来告诉GPU:数据准备好了,可以按照我的设置开始渲染,这个渲染命令就是Draw Call,讲了这么多终于回来了。

 实际上,Draw Call就是一个命令,它的发起方是CPU,接收方是GPU。当给定了一个Draw Call时,GPU就会根据渲染状态(比如材质,纹理,着色器等)和所有输入的顶点数据来进行计算,最终输出成屏幕上显示的那些像素,这个过程也会涉及到GPU流水线。如果有读者对此不清楚可以看看笔者以前的博客有详细的介绍。接下来我们继续解释Draw Call ,给开发者造成的误区认为 造成Draw Call问题的主要原因是GPU, 认为GPU上的状态切换是耗时的,其实不是的,真正的罪魁祸手是CPU。

下面我们就介绍CPU和GPU工作原理,大家先想一下,如果没有流水线,那么CPU需要等到GPU完成上一个渲染任务才能再次发送渲染命令。但这种方法显然会造成效率低下。我们需要让CPU和GPU可以并行工作,解决方法是使用一个命令缓冲区(Command Buffer)。命令缓冲区包含了一个命令队列,它是由CPU向其中添加命令,而由GPU从中读取命令,添加和读取的过程是相互独立的。命令缓冲区使得CPU和GPU可以相互独立工作。当CPU需要渲染一些对象时,他可以向命令缓冲区中添加命令,而当GPU完成了上一次的渲染任务后,它就可以从命令队列中再取出一个命令并执行它。

命令缓冲区中的命令有很多种,而Draw Call是其中一种,其它命令还有改变渲染状态等。效果如下图所示:

图中显示的是CPU与GPU通过缓冲区进行交互,Draw Call执行的是图中灰色的显示的,而白色的是改变渲染状态的,这个相对来说比较耗时间。

为什么Draw Call 多了会影响帧率?读者可以做一个实验,比如你复制1000个文本文件到另一个文件夹中,每个文件大小是100K,总计大小是10MB,这个要花费很长时间。我们再来创建一个单独的文件,它的大小是10M,然后也把它从一个文件夹复制到另一个文件夹。这次复制的时间少很多。主要原因在于,每一个复制动作需要很多额外的操作,比如分配内存等,如果复制1000个文件,他要开辟内存1000次,这个开销将会很大。

渲染过程跟这个类似,在每次调用Draw Call之前,CPU需要向GPU发送很多内容,包括数据、状态和命令等。在这一阶段,CPU要完成很多工作。一旦CPU完成了这些准备工作,GPU就可以开始本次的渲染。GPU渲染能力是很强的,渲染200个还是2000个三角网格没啥区别,因此渲染速度往往快于CPU提交命令的速度。如果需要执行的数据很多,也就是说Draw Call 数量很多,CPU就会把大量的时间花费在提交Draw Call上,造成CPU的过载,这个是需要我们避免的。

如何减少Draw Call的数量,这个在Unity开发中常见,减少Draw Call的方法很多,介绍一下批处理的方法。在前面提到过,复制文件的问题,CPU的时间都花费在准备Draw Call的工作上了。优化的想法就是把很多小的DrawCall合并成一个大的Draw Call,这就是批处理思想。

需要注意的是,合并网格是需要CPU在内存中执行的,合并的过程是需要消耗时间的。因此,批处理技术更加适合于哪些静态的物体,当然动态的如果合并的话,也需要在CPU中执行,我在以前的博客中也有介绍。要注意的是不要每一帧都去重新进行合并再发送给GPU,这对空间和时间都会造成一定的影响。

要做到减少Draw Call需要注意以下两点:

1、避免使用大量很小的网格,如果不可避免需要使用很小的网格结构,可以考虑合并,当然,模型的材质也可以考虑通用。

2、避免使用过多的材质,尽量在不同的网格之间共用同一个材质。

3、遇到有相同动作的物体,可以使用合并动态网格的方式进行优化,效果还不错。

在本文最后把动态网格合并的代码给读者展示如下:

public class CombineOpMesh : MonoBehaviour {


    void Start()
    {
        CombineToMesh(this.gameObject);
    }


    public void CombineToMesh(GameObject _go)
    {
        SkinnedMeshRenderer[] smr = _go.GetComponentsInChildren<SkinnedMeshRenderer>();
        List<CombineInstance> lcom = new List<CombineInstance>();


        List<Material> lmat = new List<Material>();
        List<Transform> ltra = new List<Transform>();


        for (int i = 0; i < smr.Length; i++ )
        {
            lmat.AddRange(smr[i].materials);
            ltra.AddRange(smr[i].bones);


            for (int sub = 0; sub < smr[i].sharedMesh.subMeshCount; sub++ )
            {
                CombineInstance ci = new CombineInstance();
                ci.mesh = smr[i].sharedMesh;
                ci.subMeshIndex = sub;
                lcom.Add(ci);
            }
            Destroy(smr[i].gameObject);
        }


        SkinnedMeshRenderer _r = _go.GetComponent<SkinnedMeshRenderer>();
        if (_r == null)
            _r = _go.AddComponent<SkinnedMeshRenderer>();


        _r.sharedMesh = new Mesh();
        _r.bones = ltra.ToArray();
        _r.materials = new Material[] { lmat[0] };
        _r.rootBone = _go.transform;
        _r.sharedMesh.CombineMeshes(lcom.ToArray(), true, false);
    }
}
实现原理是:首先去遍历每个对象的SkinnderMeshRenderer,然后将其所有的动态对象组合成一个大的对象并且将骨骼动画赋值给他,这样,我们就实现了动态对象的优化。

实现效果图对比如下,首先展示的是没有合并的动态动画的Draw Call数量:


然后再挂上文提到的合并脚本后的效果如下所示:


具体操作方式如下所示:





2017-09-15 15:52:57 a609831433 阅读数 2505
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

前言:50%自己培训学到的,50%是综合网友的优化方法,如有不足之处,烦请各位指出,谢谢。

在网上看到的一些优化,但是时间已是好几年前的,有些不适合现在用,如果照搬优化,有些效果可能会取反!

(简单讲解,不深入,以后慢慢修改增加,文章可能不太适合小白看)

个人认为优化应从3块下手:CPU、内存、GPU

-------------------------------------          CPU优化              ----------------------------------------------

1.Draw Calls(CPU调用底层图形接口):Draw Call Batching(动批)和Static Batching (静批)

Draw Call Batching(动批)  满足条件

1.一般大型手机游戏,双核的手机,Tris(面)最好小于2万,4核的手机最好不能超过4~5万左右
2.一般不关心模型是什么样子,也不关心是几个模型,只要这些模型的顶点数少于300个,并且用的是相同材质且是单pass的,就能参与动态批处理
3.缩放可能会影响bathces,也可能不影响,看unity版本,一般5.以后的版本不影响
4.只有Mesh Renderer的模型才支持动态批处理
5.Skinned Mesh Renderer 是骨骼或者人物蒙皮渲染,是不支持动批的
6.所有参与过灯光烘焙的物体,因为是静态的,所以不能动态批处理


Static Batching (静批)(一般能用静批的尽量用静批)满足条件

1.必须是静态(对于有没有烘焙,不关心)
2.无顶点要求
3.和shader无关(单pass或者双pass都无关),只和材质有关
4.静态物体是不支持缩放的,如果进行缩放,则不会静态批处理

移动端Draw Calls 优化:(重要)
1.建议Draw Calls 在100左右(双核处理器) ,四核处理器建议在200~300


2..物理方面(组件和引擎)

1.碰撞(调用最底层物理引擎,消耗cpu性能),优先使用box  collider,尽量不用mesh collider。

2.碰撞层(不需要碰撞的层,取消打勾,这个比较重要


3.帧数优化(移动端建议0.033,就是1秒钟30帧。pc端性能普遍较好,建议0.01)(至于VR和AR建议次数更多,这个值和fps相关联的,就这一句话,可能是VR和AR开发人员的福音。


4.建议选择Don‘t   Sync(关闭垂直同步),然后在C#游戏入口代码里面的Awake或者Start里面写上 

Application.targetFrameRate = XX;(移动端建议30,PC端建议60.这个重要的不要不要的,为什么移动的帧数是30?,不深入,总之不要太高,否则消耗性能不说,cpu还会发烫)

【步骤3和4请同时操作】


3.代码优化

1.少用反射,ios开发的可以忘了反射(不是不用哈,少用)

2.务必在工程发布前删除代码里面的Debug.Log和print (重要,这2个比较消耗性能)

3.不要频繁创建或实例化或销毁对象,请使用对象池(Pool)(重要)。

4.同一脚本中频繁使用的变量建议声明其为全局变量,脚本之间频繁调用的变量或方法建议声明为全局静态变量或方法。(重要)

5.不要去频繁获取组件,将其声明为全局变量.

6.用简单的“for”循环代替“foreach”循环。

7.数组、集合类元素优先使用Array,其次是List,少用ArrayList(会拆装箱操作)。

8.在循环语句力里面,不要直接访问gameobject的tag属性。比如if (go.tag == “human”)最好换成if (go.CompareTag (“human”))。因为访问物体的tag属性会在堆上额外的分配空间。如果在循环中这么处理,会留下垃圾。

9.尽量少用模运算和除法运算,比如a/5f,一定要写成a*0.2f。

10.String的相加操作,会频繁申请内存并释放,导致gc频繁,使用System.Text.StringBuilder代替

11.Update少用,少在Update里面做循环,更少做复杂操作。










2018-11-21 16:06:04 luoshao_ 阅读数 0
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

Unity3D 对于移动平台的支持无可厚非,但是也有时候用Unity3D 开发出来的应用、游戏在移动终端上的运行有着明显的效率问题,比如卡、画质等各种问题。

  影响因素:

  1. Drawcall 值过大,所需要的 GPU 的处理性能较高,从而导致CPU的计算时间过长,于是就卡了。
  2. 点、面过多,GPU 根据不同面的效果展开计算,并且CPU计算的数据也多,所以效果出来了。

  优化方式:

  1. 对于模型:Mesh 合并,有个不错的插件(DrawCall Minimizer   --->  直接上Asset Store 下载即可,免费的,而且有文档,很容易上手)。
  2. 对于UI: 尽量避免使用Unity3D自带的 GUI 换用 NGUI或者EZGUI,因为这两个UI插件对于UI中的图片处理是将UI图片放置在一个 Atlas 中,一个 Atlas 对应一个Drawcall。
  3. 对于灯光:可以使用 Unity3D 自带的  Lightmapping 插件来烘焙场景中的灯光效果到物体材质上。
  4. 对于场景:可以使用 Unity3D 自带的 Occlusion Culling 插件把静止不动的场景元素烘焙出来。
  5. 对于特效:尽量把材质纹理合并。  

  在屏幕上渲染物体,引擎需要发出一个绘制调用来访问图形API(iOS系统中为OpenGL ES)。每个绘制调用需要进行大量的工作来访问图形API,从而导致了CPU方面显着的性能开销。Unity在运行时可以将一些物体进行合并,从而用一个绘制调用来渲染他们。这一操作,我们称之为“批处理”。一般来说,Unity批处理的物体越多,你就会得到越好的渲染性能。 

  Unity中内建的批处理机制所达到的效果要明显强于使用几何建模工具(或使用Standard Assets包中的CombineChildren脚本)的批处理效果。这是因为,Unity引擎的批处理操作是在物体的可视裁剪操作之后进行的。Unity先对每个物体进行裁剪,然后再进行批处理,这样可以使渲染的几何总量在批处理前后保持不变。但是,使用几何建模工具来拼合物体,会妨碍引擎对其进行有效的裁剪操作,从而导致引擎需要渲染更多的几何面片。

  材质。只有拥有相同材质的物体才可以进行批处理。因此,如果你想要得到良好的批处理效果,你需要在程序中尽可能地复用材质和物体。如果你的两个材质仅仅是纹理不同,那么你可以通过纹理拼合操作来将这两张纹理拼合成一张大的纹理。一旦纹理拼合在一起,你就可以使用这个单一材质来替代之前的两个材质了。如果你需要通过脚本来访问复用材质属性,那么值得注意的是改变Renderer.material将会造成一份材质的拷贝。因此,你应该使用Renderer.sharedMaterial来保证材质的共享状态。 

  动态批处理。如果动态物体共用着相同的材质,那么Unity会自动对这些物体进行批处理。动态批处理操作是自动完成的,并不需要你进行额外的操作。

  1. 批处理动态物体需要在每个顶点上进行一定的开销,所以动态批处理仅支持小于900顶点的网格物体。 
  2. 如果你的着色器使用顶点位置,法线和UV值三种属性,那么你只能批处理300顶点以下的物体;如果你的着色器需要使用顶点位置,法线,UV0,UV1和切向量,那你只能批处理180顶点以下的物体。请注意:属性数量的限制可能会在将来进行改变。
  3. 不要使用缩放尺度(scale)。分别拥有缩放尺度(1,1,1)和(2,2,2)的两个物体将不会进行批处理。
  4. 统一缩放尺度的物体不会与非统一缩放尺度的物体进行批处理。使用缩放尺度(1,1,1)和 (1,2,1)的两个物体将不会进行批处理,但是使用缩放尺度(1,2,1)和(1,3,1)的两个物体将可以进行批处理。
  5. 使用不同材质的实例化物体(instance)将会导致批处理失败。
  6. 拥有lightmap的物体含有额外(隐藏)的材质属性,比如:lightmap的偏移和缩放系数等。所以,拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一部分)。
  7. 多通道的shader会妨碍批处理操作。比如,几乎unity中所有的着色器在前向渲染中都支持多个光源,并为它们有效地开辟多个通道。
  8. 预设体的实例会自动地使用相同的网格模型和材质。

  静态批处理。相对而言,静态批处理操作允许引擎对任意大小的几何物体进行批处理操作来降低绘制调用。因此,静态批处理比动态批处理更加有效,你应该尽量低使用它,因为它需要更少的CPU开销。为了更好地使用静态批处理,你需要明确指出哪些物体是静止的,并且在游戏中永远不会移动、旋转和缩放。想完成这一步,你只需要在检测器(Inspector)中将Static复选框打勾即可。使用静态批处理操作需要额外的内存开销来储存合并后的几何数据。在静态批处理之前,如果一些物体共用了同样的几何数据,那么引擎会在编辑以及运行状态对每个物体创建一个几何数据的备份。这并不总是一个好的想法,因为有时候,你将不得不牺牲一点渲染性能来防止一些物体的静态批处理,从而保持较少的内存开销。比如,将浓密森里中树设为Static,会导致严重的内存开销。静态批处理目前只支持Unity iOS Advanced。

Unity3d 性能优化

阅读数 166

Unity3D项目优化

阅读数 228