渲染
Q1:我们是手游项目,想对场景中的静态物件做一个遮挡剔除,不知道Unity自带的Occlusion Culling对性能优化的提升有多少呢?我们用Unity官方例子测试,启用Occlusion Culling后发现DrawCall、Triangle几乎没有变化。另外也想获知,Occlusion Culling的数据能否像NavMeshData那样可以动态加载呢?谢谢!
Occlusion Culling在使用后具体能提升多少,这个其实是没有明确数值的,甚至可能不升反降!这个只能题主在自己的项目中进行尝试。
一般来说,Occlusion Culling功能特别适合第一人称或第三人称跟随的平视角相机(比如传统意义上的MMO等类似游戏),且适用于在场景中存在大量的遮挡情况。因此,在城市街道漫游、峡谷漫游等特定场景中,比较推荐开启Occlusion Culling功能。
但是Occlusion Culling功能本身存在一定的性能开销,因为需要每帧均遍历烘焙的Cell来明确哪些物体需要或不需要渲染,所以场景中Cell越细,那么其查询开销也就越大。因此,如果场景中本身没有大量的遮挡关系,那么开启Occlusion Culling功能后,其节省下来的渲染耗时可能抵不上其Cell查询耗时来的大,这样就得不偿失了。
下图为我们优化过的一个案例,项目中开启了Occlusion Culling功能,由于场景过于复杂且Cell也烘焙较细,所以可以看到其Culling中的WaitingForJob耗时达到了33%。
因此,我们尝试将项目中的Occlusion Culling在运行时关闭,并在Profiler中直接查看关闭前后的对比结果(下图),可以看到,Rendering中的Draw Call、Triangles并没有变化,但其Culling开销却大幅下降。这说明,在该项目中,Occlusion Culling虽然开启但并没有起到效果,反而大幅增加了CPU端的Culling耗时。
综上所述,Occlusion Culling功能仅适合于特定项目、特定场景来进行使用,并且建议在使用前后,项目组应该多加对比,反复查看其加入后是否确实带来性能提升。
最后,Occlusion Culling的Data目前并不能动态加载,只能随场景来进行加载。因此,可以尝试创造一个拥有Occlusion Culling Data的“空场景”,然后通过LoadLevelAdditive方式来进行加载,从而来达到“动态”加载的效果。
此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/596c93da2832ee102d2ac18e
如您对该问题仍有疑问,可以转至社区进行进一步交流。
内存管理
Q2:通过Profiler.GetMonoHeapSize()获取到的堆内存,在操作UI的时候,打开某个节点比较多的UI界面,根据上面接口取到的堆内存会突然涨6~8MB,但是Profiler取不到这个数据,该怎么办呢?我不是固定打开某个界面,而是随机出现在某个界面上,这样的问题该如何入手呢?
Mono总体堆内存一次性涨6-8MB是比较正常的。Mono内存并不是随用随分配的,而是当其发现不够用时,一次性从系统中获取一段连续的内存。在游戏运行一段时间后,这个值一般是8MB。所以,题主遇到的情况很有可能是在连续操作UI界面时,Mono发现堆内存不够用了,于是就有了题主观察到的内存分配。
此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/596f3a85e7b53b286095384d
如您对该问题仍有疑问,可以转至社区进行进一步交流。
动画
Q3:我写了一个顶点动画的Shader,对物体顶点位置进行了修改,使其能够跟随相机移动,并总是出现在相机前面。当游戏运行后,开始时物体能够正常显示。相机在场景中移动一段距离后,物体便不再显示,但相机换一下朝向,物体又能显示。目前排除了面剔除的原因,在Shader中已经关闭了Cull(Cull Off),请问还可能是什么其他原因呢?
消失的原因应当是Unity的Frustum Culling引起。因为顶点动画是在shader中修改的顶点位置,而Frustum Culling是根据顶点修改之前的Mesh的bounds进行的,因此随着相机移动,Mesh实际已经出了Frustum的范围。最简单的解决方法是直接将Mesh的bounds设置足够大,让Unity始终不对其进行Culling:
mesh.bounds = new UnityEngine.Bounds(transform.position, new Vector3(float.MaxValue, float.MaxValue,
float.MaxValue));
此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/596c8cb52832ee102d2ac18c
如您对该问题仍有疑问,可以转至社区进行进一步交流。
GPU
Q4:我使用SystemInfo.graphicsDeviceName获取的GPU信息不太详细。比如ARM系列的Mali,T880 MP2与T880 MP12相差甚远,但是只能获取到T880,无法获取MP的信息。各位是否有办法?
对于获取GPU名称信息,在Android的Java层中可以利用API:GLES20.glGetString(GLES20.GLRENDERER)获取显示设备名。可以尝试在Unity中利用AndroidJavaClass(https://docs.unity3d.com/ScriptReference/AndroidJavaClass.html)来调用该API,尝试获取更详细的型号。
如果获取GPU名称的目的是判断GPU性能,可以看下SystemInfo中其他graphicsDevice相关的GPU性能信息是否够用。
此问答来自于UWA 问答社区:
https://answer.uwa4d.com/question/59688ccda5c647ad018763cf
如您对该问题仍有疑问,可以转至社区进行进一步交流。
物理模块
Q5:两个挂了Collider的物体,一个物体挂了Rigidbody,去碰撞另一物体,为什么每次OnCollisionEnter这个函数在实际还没有碰撞的时候就调用了呢?如下图,这时OnCollsionEnter已经被调用,但从图上可以看到两物体实际还没有接触,这个函数调用之后才会真正碰撞在一起。
物理系统在FixedUpdate中触发,包括OnCollisionEnter。而FixedUpdate早于Frame Rendering,因此碰撞实际已经发生,只是画面还没更新。其实在运行时这点时间差几乎应该可以忽略。
原文出处:侑虎科技
本文作者:admin
转载请与作者联系,同时请务必标明文章原始出处和原文链接及本声明。