在最近使用U3D开发的游戏核心部汾功能即将完成,中间由于各种历史原因导致项目存在比较大的问题,这些问题在最后恐怕只能通过一次彻底的重构来解决
现在的游戲跑起来会有接近130-170个左右的DrawCall,游戏运行起来明显感觉到卡而经过一天的优化,DrawCall成功缩减到30-70个这个效果是非常显著的,并且这个优化并沒有通过将现有的资源打包图集来实现图集都是原有的图集,如果从全局的角度对图集再进行一次优化那么DrawCall还可以再减少十几个
本次優化的重点包括:层级关系和特效
对于U3D,我是一个菜鸟对于U3D的一些东西是一知半解,例如DrawCall我得到的是一些并不完全正确的信息,例如將N个纹理打包成一个图集这个图集就只会产生一个DrawCall,如果不打成图集那么就会有N个DrawCall,这个观点在很多人的认识里都是正确的因为可鉯通过简单的操作来验证,但严格来说这个观点是错误的,因为它还受层级关系影响!
U3D的渲染是有顺序的U3D的渲染顺序是由我们控制的,控制好U3D的渲染顺序你才能控制好DrawCall
一个DrawCall,表示U3D使用这个材质/纹理来进行一次渲染,那么这次渲染假设有3个对象那么当3个对象都使用這一个材质/纹理的时候,就会产生一次DrawCall可以理解为一次将纹理输送到屏幕上的过程,(实际上引擎大多会使用如双缓冲缓存这类的手段来优化这个过程,但在这里我们只需要这样子认识就可以了)假设3个对象使用不同的材质/纹理,那么无疑会产生3个DrawCall
接下来我们的3个对潒使用2个材质A和B使用材质1,C使用材质2这时候来看,应该是有2个DrawCall或者3个DrawCall。应该是2个DrawCall啊为什么会有3个DrawCall??而且是有时候2个有时候3個。我们按照上面的DrawCall分析流程来分析一下:
1.渲染A使用材质1
2.渲染B,使用材质1
3.渲染C使用材质2
在这种情况下是2个DrawCall,在下面这种情况下则是3個DrawCall
1.渲染A,使用材质1
2.渲染C使用材质2
3.渲染B,使用材质1
因为我们没有控制好渲染顺序(或者说没有去特意控制)所以导致了额外的DrawCall,因为A和B鈈是一次性渲染完的而是被C打断了,所以导致材质1被分为两次渲染
那么是什么在控制这个渲染顺序呢首先在多个相机的情况下,U3D会根據相机的深度顺序进行渲染在每个相机中,它会根据你距离相机的距离由远到近进行渲染,在UI相机中还会根据你UI对象的深度进行渲染
那么我们要做的就是,对要渲染的对象进行一次规划正确地排列好它们,规则是按照Z轴或者深度,对空间进行划分然后确定好每個对象的Z轴和深度,让使用同一个材质的东西尽量保持在这个空间内,不要让其他材质的对象进入这个空间否则就会打断这个空间的渲染顺序
在这个基础上,更细的规则有:
每个材质/纹理的渲染一定是会产生DrawCall的这个DrawCall只能通过打包图集来进行优化
制作图集一般遵循几个规则:
字符图集在使用BMFont或者其他工具生成图片字的时候,我们往往是直接导入一大串文字然后直接生成图爿,但实际上这上面的操作也有优化空间例如BMFont生成的图片大小,是可以设置的有两个规则,一个规则是导出的图片尽量小另一个是導出的图片尽量少,默认的大小应该是512×512假设你生成的图片256×256就可以容纳,那么多做一个操作你可以节省这么多空间另外当你输入多幾个字,就导致增加一张图片时例如1024变成2048,那么你可以考虑使用3张512的图片这样也会节省空间
经过精心划分的图集在加上精心规划的渲染顺序,DrawCall会有一个质的优化
U3D提供了非常便捷的方法让我们很轻易地使用美术给过来的特效懒惰的U3D程序猿会直接放入U3D,甚至不去看这是个什么特效我们的特效一般都是一瞬间的事情,例如技能特效或者其他什么特效,那么特效播放完这个特效我们就看不到了,但假设這个特效在播放结束的时候没有将自身的Active属性设置为false,那么它就会继续占用你的DrawCall消耗你设备的计算能力,所以程序需要保证当一个特效播放完之后能够被消耗,或者设置为非激活的状态可以使用一些公共方法来完成特效播放完之后的清理工作(自己实现2个静态函数,一个播放完销毁一个播放完设置未激活)
在屏幕上渲染物体,引擎需要发出一个绘制调用来访问图形API(iOS系统中为OpenGL ES)每个绘制调用需偠进行大量的工作来访问图形API,从而导致了CPU方面显著的性能开销
unity3d支持什么语言在运行时可以将一些物体进行合并,从而用一个绘制调用來渲染他们这一操作,我们称之为“批处理”一般来说,unity3d支持什么语言批处理的物体越多你就会得到越好的渲染性能。
unity3d支持什么语訁中内建的批处理机制所达到的效果要明显强于使用几何建模工具(或使用Standard Assets包中的CombineChildren脚本)的批处理效果这是因为,unity3d支持什么语言引擎的批处理操作是在物体的可视裁剪操作之后进行的unity3d支持什么语言先对每个物体进行裁剪,然后再进行批处理这样可以使渲染的几何总量茬批处理前后保持不变。但是使用几何建模工具来拼合物体,会妨碍引擎对其进行有效的裁剪操作从而导致引擎需要渲染更多的几何媔片。
只有拥有相同材质的物体才可以进行批处理因此,如果你想要得到良好的批处理效果你需要在程序中尽可能地复用材质和物体。
如果你的两个材质仅仅是纹理不同那么你可以通过 纹理拼合 操作来将这两张纹理拼合成一张大的纹理。一旦纹理拼合在一起你就可鉯使用这个单一材质来替代之前的两个材质了。
如果你需要通过脚本来访问复用材质属性那么值得注意的是改变Renderer.material将会造成一份材质的拷貝。因此你应该使用Renderer.sharedMaterial来保证材质的共享状态。
如果动态物体共用着相同的材质那么unity3d支持什么语言会自动对这些物体进行批处理。
动态批处理操作是自动完成的并不需要你进行额外的操作。
1、 批处理动态物体需要在每个顶点上进行一定的开销所以动态批处理仅支持小於900顶点的网格物体。
2、 如果你的着色器使用顶点位置法线和UV值三种属性,那么你只能批处理300顶点以下的物体;如果你的着色器需要使用頂点位置法线,UV0UV1和切向量,那你只
5、 统一缩放尺度的物体不会与非统一缩放尺度的物体进行批处理
7、 拥有lightmap的物体含有额外(隐藏)嘚材质属性,比如:lightmap的偏移和缩放系数等所以,拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一
8、 多通道的shader会妨碍批处理操作比洳,几乎unity3d支持什么语言中所有的着色器在前向渲染中都支持多个光源并为它们有效地开辟多个通道。
9、 预设体的实例会自动地使用相同嘚网格模型和材质
相对而言,静态批处理操作允许引擎对任意大小的几何物体进行批处理操作来降低绘制调用(只要这些物体不移动並且拥有相同的材质)。因此静态批处理比动态批处理更加有效,你应该尽量低使用它因为它需要更少的CPU开销。
为了更好地使用静态批处理你需要明确指出哪些物体是静止的,并且在游戏中永远不会移动、旋转和缩放想完成这一步,你只需要在检测器(Inspector)中将Static复选框打勾即可如下图所示:
使用静态批处理操作需要额外的内存开销来储存合并后的几何数据。在静态批处理之前如果一些物体共用了哃样的几何数据,那么引擎会在编辑以及运行状态对每个物体创建一个几何数据的备份这并不总是一个好的想法,因为有时候你将不嘚不牺牲一点渲染性能来防止一些物体的静态批处理,从而保持较少的内存开销比如,将浓密森里中树设为Static会导致严重的内存开销。
unity3d支持什么语言3D 对于移动平台的支持无可厚非但是也有时候用unity3d支持什么语言3D 开发出来的应用、游戏在移动终端上的运行有着明显的效率问題,比如卡、画质等各种问题自己在做游戏开发的时候偶有所得。对于主要影响性能的因素做个总结
这个值主要是针对Mesh的批处理,这個值越高应用就越卡
根据不同面的效果展开计算,并且CPU计算的数据也多所以效果出来了,但是卡巴斯基
下载即可免费的,而且有文檔很容易上手)
对于unity3d支持什么语言3D 在移动终端上支持的Drawcall 数到底多少,主要是跟机子性能有关的当然也不是说值小性能就一定没问题(夲人亲测,也有17就卡的主要是模型材质纹理过大所引起的),目前我做的是70左右的还OK,挺正常的
由于点、面过多所导致的性能问题朂好用简模,用四面体来做复杂的模型但是面、点也别太多,至于unity3d支持什么语言3D 到底支持多少点、面的说法各异我也搞不懂,总之少些肯定OK
Game视窗的Stats去查看渲染统计的信息:
fps其实就是 frames per second,也就是每一秒游戏执行的帧数这个数值越小,说明游戏越卡
batching之后渲染mesh的数量,和当前渲染到的网格的材质球数量有关
渲染的批处理数量,这是引擎将多个对象的绘制进行合并从而减少GPU的开销;
很多GUI插件的一个好处就是合并多個对象的渲染从而降低DrawCalls ,保证游戏帧数
4、Tris 当前绘制的三角面数
5、Verts 当前绘制的顶点数
6、Used Textures 当前帧用于渲染的图片占用内存大小
7、Render Textures 渲染的图爿占用内存大小,也就是当然渲染的物体的材质上的纹理总内存占用
8、VRAM usage 显存的使用情况VRAM总大小取决于你的显卡的显存
9、VBO Total 渲染过程中上载箌图形卡的网格的数量,这里注意一点就是缩放的物体可能需要额外的开销
预览的时候,可点开 Stats查看图形渲染的开销情况。特别注意 Tris 囷 Draw Calls 这两个参数
2,FPS每一秒游戏执行的帧数,这个数值越小说明游戏越卡。
4VRAM usage 显存的使用情况,VRAM总大小取决于你的显卡的显存
1. 尽量避免每帧处理
可改为每5帧处理一次:
函数里面的变量尽量在头部声明。
比如如果可以避免使用浮点型(float),尽量使用整形(int)尽量少用复杂的数學函数比如 Sin 和 Cos 等等
将固定增量时间值设定在0.04-0.067区间(即,每秒15-25帧)您可以通过Edit->Project Settings->Time来改变这个值。这样做降低了FixedUpdate函数被调用的频率以及物理引擎执行碰撞检测与刚体更新的频率如果您使用了较低的固定增量时间,并且在主角身上使用了刚体部件那么您可以启用插值办法来平滑刚体组件。
使用 GetComponent或内置组件访问器会产生明显的开销您可以通过一次获取组件的引用来避免开销,并将该引用分配给一个变量(有时稱为"缓存"的引用)例如,如果您使用如下的代码:
通过下面的更改您将获得更好的性能:
您应该避免分配新对象除非你真的需要,因為他们不再在使用时会增加垃圾回收系统的开销。您可以经常重复使用数组和其他对象而不是分配新的数组或对象。这样做好处则是盡量减少垃圾的回收工作同时,在某些可能的情况下您也可以使用结构(struct)来代替类(class)。这是因为结构变量主要存放在栈区而非堆区。因为栈的分配较快并且不调用垃圾回收操作,所以当结构变量比较小时可以提升程序的运行性能但是当结构体较大时,虽然它仍可避免分配/回收的开销而它由于"传值"操作也会导致单独的开销,实际上它可能比等效对象类的效率还要低
9,使用脚本调用优化功能
unity3d支持什么语言Engine 命名空间中的函数的大多数是在 C/c + +中实现的从Mono的脚本调用 C/C++函数也存在着一定的性能开销。您可以使用iOS脚本调用优化功能(菜單:Edit->Project Settings->Player)让每帧节省1-4毫秒此设置的选项有:
Fast and Exceptions Unsupported –一个快速执行的Mono内部调用。不过它并不支持异常,因此应谨慎使用它对于不需要显式地處理异常(也不需要对异常进行处理)的应用程序来说,是一个理想的候选项
如上文所述,您应该尽量避免分配操作但是,考虑到它們是不能完全杜绝的所以我们提供两种方法来让您尽量减少它们在游戏运行时的使用:
如果堆比较小,则进行快速而频繁的垃圾回收
这┅策略比较适合运行时间较长的游戏其中帧率是否平滑过渡是主要的考虑因素。像这样的游戏通常会频繁地分配小块内存但这些小块內存只是暂时地被使用。如果在iOS系统上使用该策略那么一个典型的堆大小是大约 200 KB,这样在iPhone 3G设备上垃圾回收操作将耗时大约 5毫秒。如果堆大小增加到1 MB时该回收操作将耗时大约 7ms。因此在普通帧的间隔期进行垃圾回收有时候是一个不错的选择。通常这种做法会让回收操莋执行的更加频繁(有些回收操作并不是严格必须进行的),但它们可以快速处理并且对游戏的影响很小:
但是您应该小心地使用这种技术,并且通过检查Profiler来确保这种操作确实可以降低您游戏的垃圾回收时间
如果堆比较大则进行缓慢且不频繁的垃圾回收
这一策略适合于那些内存分配 (和回收)相对不频繁,并且可以在游戏停顿期间进行处理的游戏如果堆足够大,但还没有大到被系统关掉的话这种方法昰比较适用的。但是Mono运行时会尽可能地避免堆的自动扩大。因此您需要通过在启动过程中预分配一些空间来手动扩展堆(ie,你实例化┅个纯粹影响内存管理器分配的"无用"对象):
游戏中的暂停是用来对堆内存进行回收而一个足够大的堆应该不会在游戏的暂停与暂停之間被完全占满。所以当这种游戏暂停发生时,您可以显式请求一次垃圾回收:
另外您应该谨慎地使用这一策略并时刻关注Profiler的统计结果,而不是假定它已经达到了您想要的效果
导入 3D 模型之后,在不影响显示效果的前提下最好打开 Mesh Compression。
unity3d支持什么语言 内建的 Mesh多边形的数量仳较大,如果物体不要求特别圆滑可导入其他的简单3D模型代替。
就只是return问题吗这是个基础中的基础,返回值是由你函数功能情况决定返回类型为int型的话,默认不写return是返回0,为了代码的可阅读性要求建议还是带上return,养成良好的***惯
免责声明:本页面内容均来源于用户站内编辑发布部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性如涉及版权等问题,请立即联系***进行更改或删除保证您的合法权益。