Unity3d优化[转]

检测方式:

 

Unity Manual > Advanced > Optimizing Graphics Performance > Rendering Statistics Window

Unity手册->高级->优化图形性能->渲染统计窗口

The Game View has a Stats button top right. When this Stats button is pressed, an overlay window is displayed with realtime rendering statistics. This is very useful for Optimizing Graphics Performance. Additionally, Profiler shows some rendering statistics.

游戏视图有一个统计按钮在右上角。当这个按钮被按下统计,一个重叠窗口与实时渲染的统计数字显示。这是非常有用的优化的图形性能。此外,分析器显示了一些渲染的统计参数。

Unity3D高级手册0603:渲染统计窗口

Rendering Statistics Window  渲染统计窗口

Statistics window contains the following information:  通体窗口包含如下的信息:

Time per frame and FPS

每帧时间和FPS

How much time it takes to process and render one game frame (and resulting FPS). Note that this number only includes frame update and rendering of the game view; and does not include time taken in the editor to draw the scene view, inspector and other editor-only processing.

花费多少的时间去处理进程和渲染一个游戏的帧(以及FPS结果)。请注意,这个数字只包括帧更新和游戏图像生成;,不包括在编辑器中绘制场景视图,检视器和其它编辑器只处理时间。

Draw Calls

绘制调用

How many objects are drawn in total. This accumulates objects that are drawn multiple times as well, for example some object that is affected by pixel lights will add several draw calls.

总共有多少对象被绘制。这种积累的对象也被绘制多次,例如一些受影响对象通过像素光源绘制将添加几个绘制调用。

Tris andVerts

三角形和顶点

Number of triangles and vertices drawn. This is mostly important when optimizing for low-end hardware

三角形和顶点数目绘制。这主要是重要的当优化低端硬件时。

Used Textures

使用纹理

Count and memory size of textures used when drawing this frame.

纹理的数量和内存大小使用当绘制这个帧时。

Render Textures

渲染纹理

Count and memory size of Render Textures that are created. Also displays how many times active Render Texture was switched during this frame.

所创建的纹理渲染的数量和内存大小。也显示有多少次激活的渲染纹理被在这个帧期间交换。

Screen

屏幕

Size, anti-aliasing level and memory taken by the screen itself.

大小,图形保真水平和内存携带通过屏幕它自身。

VRAM usage

显存使用率

Approximate bounds of current video memory (VRAM) usage. Also shows how much video memory your graphics card has.

当前视频内存(显存)使用近似边界。也显示你显卡有多少视频内存。

VBO total

VBO总计

Number of unique meshes (vertex buffers) that are uploaded to the graphics card. Each different model will cause new VBO to be created. In some cases scaled objects will cause additional VBOs to be created.

独特网格的数量(顶点缓冲器)上传至显卡。每一个不同的模型将导致新的VBO被创建。在某些情况下伸缩对象将造成额外VBOS被创建。

VB uploads

VB 上载

Count and size of vertex data changed this frame. Dynamic geometry, like particles or skinned meshes, will contribute to this, as well as terrain LOD changing, etc.

这个帧的顶点数据更改的数量和大小。动态几何结构、像粒子和皮肤网格,将有助于这一点,以及地形LOD的变化等。

IB uploads

IB 上载

Count and size of triangle data changed this frame. Dynamic geometry, like particles or skinned meshes, will contribute to this, as well as terrain LOD changing, etc.

这个帧的三角形数据更改的数量和大小。动态几何结构,像粒子和皮肤网格,将有助于这一点,以及地形LOD的变化等。

Visible Skinned Meshes

可视皮肤网格

How many skinned meshes are rendered.

多少皮肤网格被渲染。

Animations

动画

How many animations are playing.

多少动画 被播放。

注意事项:

1,运行时尽量减少 Tris 和 Draw Calls

预览的时候,可点开 Stats,查看图形渲染的开销情况。特别注意 Tris 和 Draw Calls 这两个参数。

一般来说,要做到:

Tris 保持在 7.5k 以下,有待考证。

Draw Calls 保持在 20 以下,有待考证。

2,FPS,每一秒游戏执行的帧数,这个数值越小,说明游戏越卡。

3,Render Textures 渲染的图片占用内存大小。

4,VRAM usage 显存的使用情况,VRAM总大小取决于你的显卡的显存。

 

二,代码优化

0. 在使用数组或ArrayList对象时应当注意:

避免

for(int i=0;i<myArray.Length;i++)
 {
}

可以改为:

length=myArray.Length;

for(int i=0;i<length;i++)
{

}

1. 尽量避免每帧处理

比如:

function Update() { DoSomeThing(); }

可改为每5帧处理一次:

function Update() 
{
     if(Time.frameCount % 5 == 0) 
    { 
        DoSomeThing(); 
    } 
}

 

2. 定时重复处理用 InvokeRepeating 函数实现

比如,启动0.5秒后每隔1秒执行一次 DoSomeThing 函数:

function Start() 
{ 
    InvokeRepeating("DoSomeThing", 0.5, 1.0); 
}

 

3. 优化 Update, FixedUpdate, LateUpdate 等每帧处理的函数

函数里面的变量尽量在头部声明。

比如:

function Update() 
{
     var pos: Vector3 = transform.position; 
}

可改为

private var pos: Vector3; 
function Update()
{ 
    pos = transform.position; 
}

 

4. 主动回收垃圾

给某个 GameObject 绑上以下的代码:

function Update() 
{ 
    if(Time.frameCount % 50 == 0) 
    { 
        System.GC.Collect(); 
    } 
}

 

5. 优化数学计算

比如,尽量避免使用float,而使用int,特别是在手机游戏中,尽量少用复杂的数学函数,比如sin,cos等函数。改除法/为乘法,例如:使用x*0.5f而不是 x/2.0f 。

 

6,减少固定增量时间

将固定增量时间值设定在0.04-0.067区间(即,每秒15-25帧)。您可以通过Edit->Project Settings->Time来改变这个值。这样做降低了FixedUpdate函数被调用的频率以及物理引擎执行碰撞检测与刚体更新的频率。如果您使用了较低的固定增量时间,并且在主角身上使用了刚体部件,那么您可以启用插值办法来平滑刚体组件。

7,减少GetComponent的调用

使用 GetComponent或内置组件访问器会产生明显的开销。您可以通过一次获取组件的引用来避免开销,并将该引用分配给一个变量(有时称为"缓存"的引用)。例如,如果您使用如下的代码:

function Update () 
{
    transform.Translate(0, 1, 0);
}

 

通过下面的更改您将获得更好的性能: 

复制代码
var myTransform : Transform;

function Awake () 
{
    myTransform = transform;
}

function Update () 
{
    myTransform.Translate(0, 1, 0);
}
复制代码

 

8,避免分配内存

您应该避免分配新对象,除非你真的需要,因为他们不再在使用时,会增加垃圾回收系统的开销。您可以经常重复使用数组和其他对象,而不是分配新的数组或对象。这样做好处则是尽量减少垃圾的回收工作。同时,在某些可能的情况下,您也可以使用结构(struct)来代替类(class)。这是因为,结构变量主要存放在栈区而非堆区。因为栈的分配较快,并且不调用垃圾回收操作,所以当结构变量比较小时可以提升程序的运行性能。但是当结构体较大时,虽然它仍可避免分配/回收的开销,而它由于"传值"操作也会导致单独的开销,实际上它可能比等效对象类的效率还要低。

 

9,使用iOS脚本调用优化功能

UnityEngine 命名空间中的函数的大多数是在 C/c + +中实现的。从Mono的脚本调用 C/C++函数也存在着一定的性能开销。您可以使用iOS脚本调用优化功能(菜单:Edit->Project Settings->Player)让每帧节省1-4毫秒。此设置的选项有:

Slow and Safe – Mono内部默认的处理异常的调用

 

Fast and Exceptions Unsupported –一个快速执行的Mono内部调用。不过,它并不支持异常,因此应谨慎使用。它对于不需要显式地处理异常(也不需要对异常进行处理)的应用程序来说,是一个理想的候选项。

 

10,优化垃圾回收 

如上文所述,您应该尽量避免分配操作。但是,考虑到它们是不能完全杜绝的,所以我们提供两种方法来让您尽量减少它们在游戏运行时的使用:

如果堆比较小,则进行快速而频繁的垃圾回收

这一策略比较适合运行时间较长的游戏,其中帧率是否平滑过渡是主要的考虑因素。像这样的游戏通常会频繁地分配小块内存,但这些小块内存只是暂时地被使用。如果在iOS系统上使用该策略,那么一个典型的堆大小是大约 200 KB,这样在iPhone 3G设备上,垃圾回收操作将耗时大约 5毫秒。如果堆大小增加到1 MB时,该回收操作将耗时大约 7ms。因此,在普通帧的间隔期进行垃圾回收有时候是一个不错的选择。通常,这种做法会让回收操作执行的更加频繁(有些回收操作并不是严格必须进行的),但它们可以快速处理并且对游戏的影响很小:

if (Time.frameCount % 30 == 0)
{
    System.GC.Collect();
}

 

但是,您应该小心地使用这种技术,并且通过检查Profiler来确保这种操作确实可以降低您游戏的垃圾回收时间

如果堆比较大,则进行缓慢且不频繁的垃圾回收

这一策略适合于那些内存分配 (和回收)相对不频繁,并且可以在游戏停顿期间进行处理的游戏。如果堆足够大,但还没有大到被系统关掉的话,这种方法是比较适用的。但是,Mono运行时会尽可能地避免堆的自动扩大。因此,您需要通过在启动过程中预分配一些空间来手动扩展堆(ie,你实例化一个纯粹影响内存管理器分配的"无用"对象): 

复制代码
function Start() 
{
    var tmp = new System.Object[1024];
    // make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
    for (var i : int = 0; i < 1024; i++)
    {
        tmp[i] = new byte[1024];
        // release reference
        tmp = null;
    } 
}
复制代码


游戏中的暂停是用来对堆内存进行回收,而一个足够大的堆应该不会在游戏的暂停与暂停之间被完全占满。所以,当这种游戏暂停发生时,您可以显式请求一次垃圾回收:

 System.GC.Collect();

 另外,您应该谨慎地使用这一策略并时刻关注Profiler的统计结果,而不是假定它已经达到了您想要的效果。

11、如果可能,将GameObject上不必要的脚本disable掉。如果你有一个大的场景在你的游戏中,并且敌方的位置在数千米意外,这是你可以disable你的敌方AI脚本直到它们接近摄像机为止。一个好的途径来开启或关闭GameObject是使用SetActiveRecursively(false),并且球形或盒型碰撞器设为trigger。

12、删除空的Update方法。当通过Assets目录创建新的脚本时,脚本里会包括一个Update方法,当你不使用时删除它。

13、引用一个游戏对象的最合乎逻辑的组件。有人可能会这样写someGameObject.transform,gameObject.rigidbody.transform.gameObject.rigidbody.transform,但是这样做了一些不必要的工作,你可以在最开始的地方引用它,像这样:

privateTransform myTrans;

void Start()

{

    myTrans=transform;

}

 

14、协同是一个好方法。可以使用协同程序来代替不必每帧都执行的方法。(还有InvokeRepeating方法也是一个好的取代Update的方法)。

15、尽可能不要再Update或FixedUpdate中使用搜索方法(例如GameObject.Find()),你可以像前面那样在Start方法里获得它。

16、不要使用SendMessage之类的方法,他比直接调用方法慢了100倍,你可以直接调用或通过C#的委托来实现。

17、使用JavaScript或Boo语言时,你最好确定变量的类型,不要使用动态类型,这样会降低效率,你可以在脚本开头使用#pragmastrict 来检查,这样当你编译你的游戏时就不会出现莫名其妙的错误了。

 

 

三,模型

1,压缩 Mesh

导入 3D 模型之后,在不影响显示效果的前提下,最好打开 Mesh Compression。

Off, Low, Medium, High 这几个选项,可酌情选取。

2,避免大量使用 Unity 自带的 Sphere 等内建 Mesh

Unity 内建的 Mesh,多边形的数量比较大,如果物体不要求特别圆滑,可导入其他的简单3D模型代替。

posted @   MATU  阅读(426)  评论(0编辑  收藏  举报
(评论功能已被禁用)
点击右上角即可分享
微信分享提示