位置: 编程技术 - 正文

Unity 3D 性能优化 (一)(unity gpu优化)

发布时间:2024-02-27

推荐整理分享Unity 3D 性能优化 (一)(unity gpu优化),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:unity性能优化全攻略,unity3d ugui优化,unity3d ugui优化,unity3d ugui优化,unity3d ugui优化,unity性能优化全攻略,unity3d性能优化,unity3d性能优化之贴图科普篇,内容如对您有帮助,希望把文章链接给更多的朋友!

听到过很多用Unity 3D开发游戏的程序员抱怨引擎效率太低,资源占用太高,包括我自己在以往项目的开发中也头疼过。最近终于有了空闲,可以仔细的研究一下该如何优化Unity 3D下的游戏性能。其实国外有不少有关U3D优化的资料,Unity官方的文档中也有简略的章节涉及这方面的内容,不过大多都是以优化美术资源为主,比如贴图的尺寸,模型静态及动态的batch以减少draw call,用lightmap替代动态光影,不同渲染模式在不同环境下的性能等等。鉴于此,加上美术资源方面的东西本人不是特别了解,所以都撇开不谈,这里先试着分析分析U3D脚本中常用代码段的执行效率

GetComponent

这是一个U3D脚本中使用频率最高的函数之一,这一族函数包括GetComponent,GetComponents,GetComponentInChildren,GetComponentsInChildren以及他们的泛型版本,此外GameObject类以及Component类上的很多属性也可以归于这一范畴,比如Component类的gameObject属性,GameObject类和Component类都有的transform属性等等这一系列从GameObject实例以及Component实例上获取其他挂载的内建组件的属性接口。

先来看看GetComponent函数的几种重载形式:

[csharp] view plaincopyComponent GetComponent(Type type); T GetComponent<T>() where T : Component; Component GetComponent(string type);

通过ILSpy查看UnityEngine部分源码,发现泛型形式的GetComponent其实不过是在函数体中对泛型类型T调用了typeof,然后就直接调用了非泛型形式的GetComponent,因此在此不对泛型形式的GetComponent函数做讨论。下面设计一个小实验来看看两种不同GetComponent函数的效率,以及对GetComponent的不同使用方式会带来什么样的影响:

设计实验——实验执行的主要过程是对同一个gameObject连续获取同一类型的Component 8××次,统计不同方法下的时间开销,单位是毫秒。在实验用的gameObject上一共挂在了五个各不相同的组件,所有的实验操作都是获取这五个组件中的第一个。

方案一,最直接的方式,直接在循环中对gameObject调用GetComponent(Type type)方法;

方案二,同样直接的方式,直接在循环中对gameObject调用GetComponent(string type)方法;

方案三,在循环外事先以GetComponent获取gameObject上的Component并缓存引用,然后在循环中直接访问缓存的引用;

方案四,利用C#扩展方法,对GameObject类添加扩展方法,以一个静态字典Dictionary<GameObject, Component>存储gameObject和gameObject上要取用的Component的键&#;对,然后在扩展方法里做字典查询以获得Component;

实验结果——方案一约ms,方案二约ms,方案三约ms,方案四约ms。

(可能有人会对方案四抱有怀疑,担心字典中gameObject数量会影响查询效率,虽然我可以直接告诉你正常游戏里可能同时存在的GameObject数据量下对字典查询根本没有能够被觉察到的影响,但还是以数据来说明问题:

继续设计子实验,针对方案四,调整场景中gameObject的数量,每个gameObject上都挂载上述实验里的五个组件,并且都向字典中注册,对每种gameObject数量的情况都执行上述实验里的8××次组件访问。

子实验结果——1个gameObject时约ms,5个gameObject时约ms,个gameObject时约ms,个gameObject约ms,个gameObject时约ms,个gameObject时还是约ms,此时向字典中注册所消耗的时间已经远远大于之后进行的循环的消耗。其实熟悉C#字典表的人根本不会有疑问,字典是散列表,查询复杂度O(1)。)

由上述实验可以得出结论,如果要获取一个gameObject上挂载的某个组件,在逻辑允许或者架构允许的情况下尽量事先缓存这个组件的引用,这是最高效的做法,开销可以忽略不计;假如情况不允许事先缓存引用,那么在调用频率不是很频繁的情况下可以使用GetComponent<T>()或者GetComponent(Type type)的重载形式;如果确实调用比较频繁,那么最好是自己对GameObject或者Component类进行扩展,以字典查询代替每次的GetComponent调用,毕竟效率稍微高那么一点点(当然了,如果组件是动态的,那么这个办法就不适用了,还是乖乖的用GetComponent);而GetComponent(string type)这个重载如无必要就不要使用,因为它每次调用时都必须进行类型反射,以至于效率只有另外两个重载形式的十分之一不到,即便是只能以字符串的形式得知所需组件的类型,也可以事先手动进行类型反射,而不是在频繁的GetComponent时直接传递字符串参数,只有一种情况下不得不使用GetComponent(string type)这个重载形式,那就是:每一次调用前都只能以字符串的形式的到组件类型,而且每一次调用前所获得到的组件类型是无法预测的,这中情况下手动做类型反射跟直接调用GetComponent没有区别。

看完GetComponent族函数之后,接下来就是GameObject类和Component类内置的组件访问属性。

在实际脚本代码编写中,你是否经常这样一长串代码就轻易写出来了:

[csharp] view plaincopyVector3 pos = gameObject.transform.position; gameObject.collider.enabled = false;

以我们的直觉,GameObject类和Component类所提供的这些属性应该都是直接访问的事先缓存好的组件引用,因此对这些属性的使用便无所顾忌。但是事情真的是如我们所想的那样吗?如果我告诉你,有时候哪怕是用GetComponent函数的string参数形式都会比使用这些属性来的要快,你相信么?还是用实验数据说话吧。

Unity 3D 性能优化 (一)(unity gpu优化)

设计实验——对某gameObject上的Transform组件,采用不同的方法,访问8××次。

方案一,实现缓存gameObject上transform组件的引用,然后所有访问都直接取用缓存的引用;

方案二,在脚本中直接以Component类的transform属性调用的方式访问(U3D脚本都是从MoniBehaviour类派生,而MonoBehaviour又派生自Component类,所以在脚本中可以直接访问transform属性,这一点相信很多人都知道);

方案三,在脚本中以gameObject.transform的形式访问组件(注意哦,很多人都有这个习惯,觉得组件是gameObject的组件,所以访问时都喜欢加上gameObject);

方案四,在脚本中以GetComponent<Transform>()函数访问组件;

实验结果——方案一约ms,方案二约ms,方案三约ms,方案四约ms。

吃惊吧?transform属性访问的开销居然比直接访问引用要大这么多!而且通过gameObject转一道手之后开销居然又增加了这么多!不过还好,直接属性调用还是比用GetComponent要快的多……别太早下结论,Transform组件在每个GameObject实例上都有,对它的访问是不会失败的,那么如果被访问的组件在GameObject上不存在的时候呢?比如访问一个Rigidbody组件,而gameObject上没有挂载这样的组件,这时有会怎样?接着看实验。

设计实验——尝试对某gameObject上的Rigidbody组件进行访问8××次。

方案一,gameObject上确实挂载了Rigidbody组件,事先缓存组件的引用,访问时取用缓存的引用;

方案二,gameObject上确实挂载了Rigidbody组件,脚本中以Component类的rigidbody属性访问组件;

方案三,gameObject上确实挂载了Rigidbody组件,脚本中以gameObject.rigidbody的方式访问组件;

方案四,gameObject上确实挂载了Rigidbody组件,脚本中以GetComponent<Rigidbidy>()访问组件;

方案五,gameObject上没有Rigidbody组件,事先缓存组件(当然获取到的是null),访问时取用引用;

方案六,gameObject上没有Rigidbody组件,脚本中以Component类的rigidbidy属性访问组件;

方案七,gameObject上没有Rigidbody组件,脚本中以gameObject.rigidbody方式访问组件;

方案八,gameObject上没有Rigidbody组件,脚本中以GetComponent<Rigidbody>()访问组件;

实验结果——方案一约ms,方案二约ms,方案三约ms,方案四约ms,方案五约ms,方案六不少于ms,方案七不少于ms,方案八约ms。

更吃惊了吧?这一次的实验,前四组跟上一次实验差别不太大,但对rigidbody属性的访问还是要比transform属性慢了一点,后四组数据才是吃惊的根源,在组件不存在的情况下,通过属性访问组件居然会有如此大的额外开销!相比之下,GetComponent方法倒是不在乎组件是否真的存在,开销一如既往。

由于属性实现的代码无法通过ILSpy查看,所以在这里我只能用猜的了。首先是,U3D在实现这些组件访问属性的时候,必然做了各种查询和容错处理,绝非简单的缓存和取用引用那么简单,这也是属性访问比事先缓存引用的访问方式要慢那么多的原因;其次,Transform组件在每个GameObject实例上都必然存在,因此transform属性的实现比其他组件访问属性的实现必然要少那么一些步骤,这就造成对transform属性的访问要比其他组件属性快上一些;最后,当组件不存在时,对组件属性的访问应该是走入了大量的容错处理代码,这就造成这种情况下属性访问开销大增。

从这个实验又可以得出结论,我们的脚本代码里经常会需要访问gameObject引用或者某个组件的引用,最好的方式当然是在脚本Awake的时候就把这些可能访问的东西都缓存下来;如果需要访问临时gameObject实例的某属性或者临时某组件的gameObject实例,在能够确保组件一定存在的情况下,可以用属性访问,毕竟它们比GetComponent要快上一倍,但是如果不能确定组件是否存在,甚至是需要对组件的存在性做判断时,一定不要用对属性访问结果判空的方式,而要用GetComponent,这里面节省的开销不是一点半点。

Unity学习笔记之五为Prefab添加材质 本次笔记中,我们将利用unity来创建并使用材质,把材质添加到我们的Prefab中去。这一系列教程以及素材均参考自人人素材翻译组出品的翻译教程《Unity

Unity3d 换装 之 模型动画分离 在手游中换装成了越来越不可缺的一个功能,毫无疑问各式各样的时装为游戏增添了不同的色彩。对于2D手游,或许是更换对应的序列帧,也或许是如同

unity3d游戏开发经验之对于关卡类游戏的技巧 过关类游戏在单机类游戏中出现会比较多,但多以休闲为主,比如《CandyCrush》、《AngryBirds》、《PVZ》、《小鳄鱼顽皮爱洗澡》、《TinyThief》等经典休闲

标签: unity gpu优化

本文链接地址:https://www.jiuchutong.com/biancheng/381502.html 转载请保留说明!

上一篇:Unity3d IOS 64 IL2CPP迁移之 AStarPath JosnFX 错误

下一篇:Unity学习笔记之五为Prefab添加材质(unity教程完整版)

  • 原材料报废可以退税吗
  • 税务会计的工作内容和心得
  • 收入增长率的计算方法
  • 应付职工薪酬工资贷方有余额要怎么调整
  • 累计折旧贷方余额是负数表示什么
  • 外汇税收怎么缴纳增值税
  • 保证金转租金的会计处理
  • 溢价或者折价购买债券的会计处理.
  • 固定资产损失如何计提
  • 出售股票会计怎么做分录
  • 电力设备维护费增值税税率
  • 所得税费用税率规定
  • 金三地税系统如何安装客户端插件?
  • 一般纳税人企业所得税政策最新2023
  • 利润表反映了哪些情况
  • 残保金和工会经费
  • 基础研究投入费用包含工资吗
  • 需要缴纳消费税的委托加工存货,由受托方
  • 托收承付结算的付款期均为三天
  • 清算资本公积中的股本溢价应该怎么处理
  • 收到预收款项
  • 支付宝国际驾照有效期是多久
  • win11怎么关闭系统自动更新
  • 公司强制要求转部门合法吗
  • 腾讯手游助手玩不了金铲铲
  • 电商第三方平台规则的特点
  • 公司注册资金存在风险吗
  • 银行承兑汇票挂失手续费收费标准
  • 消费者取得哪种权利
  • 企业股权投资收益缴纳什么税
  • 招待费增值税能抵扣吗
  • 水利建设基金申报表哪里
  • 会计年报表怎么做
  • yii2实现根据时间搜索的方法
  • stable Diffusion安装教程
  • html调查问卷简单代码
  • npm install或npm i后没有依赖包node_modules?
  • lama羊驼
  • 用代码说话
  • x-s和web_session
  • carplcy车载有什么用
  • 请求转发与重定义的区别
  • 企业领用低值易耗品计入
  • 股东投资款超过注册资金的案例
  • 非流动资产基金对应的新科目
  • 企业应付职工薪酬
  • mongodb常见问题
  • 免税农产品有哪些类型
  • mysql安装问题
  • 企业的预付账款属于金融资产吗
  • MySQL错误什么意思
  • 注会考试模拟机考
  • 建安企业用什么会计制度
  • 上月未记账,本月同样可以记账
  • 零售行业折扣销售方案
  • 固定资产的主要特征
  • 出口转内销账务处理以前年度
  • 企业备用金怎么做账
  • 现金日记账的日期栏是指记账凭证的日期
  • 根据日期算时间
  • 将哪一linux文件系统引入
  • windows tasks文件夹
  • ubuntu下安装deb文件
  • 打开本地搜索
  • win7系统怎么禁用数字签名
  • xp系统不能正常启动怎么修复
  • win10系统自带的浏览器叫什么
  • cocos2dx4.0教程
  • jquery操作html代码
  • bootstrap需要学多久
  • jquery easyui有哪些特点
  • shell检查语法错误
  • bat注销命令
  • linux创建用户的命令是什么
  • python设计gui
  • python如何获取
  • 分支机构如何变更为独立纳税人?
  • 装修费也要缴纳房产税吗
  • 辽宁省地方税务局公告2014年第10号
  • 车辆完税证明有啥用
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号