项目研发常用的优化策略——遮挡剔除(Occlusion Culling)
前言:我们在本次的博客中讨论我们游戏项目研发的过程中为解决项目卡顿、死机、移动设备热量高等问题。对于一个Unity初学者来说,或者仅仅满足于项目功能的具体的实现上。而一个中高级的游戏研发人员则绝对不能仅仅满足于此。
一:摄像机的剔除的距离
Camera.main.layerCullDistances 属性用来设置摄像机基于层的消隐距离。摄像机可以通过层(GameObject.Layer)的方式来设置不同层物体的消隐距离。但是这个距离必须是小于或者等于摄像机的FarClippingPlanes才有效。我们同样在Layer中增加一个层Cube层,属于第8层。如图所示:
(1):在我们的项目中创建一个立方体和球体。并把立方体的Layer设置为Cube,如图所示:
(2):我们创建一个脚本Demo18_OcclusionCulling.cs,并把脚本挂载在摄像机上。脚本代码如下:
public class Demo18_OcclusionCulling : MonoBehaviour { public Transform Sphere; //球体的位置 void Start() { //定义大小为32的一维数组,用来存储所有层的剔除信息 float[] distance = new float[32]; //设置第九层层的剔除的距离 distance[8] = Vector3.Distance(transform.position, Sphere.position); //将数字赋给摄像机的layerCullDistances Camera.main.layerCullDistances = distance; } void Update() { //摄像机远离物体进行测试 transform.Translate(-transform.forward * Time.deltaTime); } }//class_end
(3):进行脚本的测试:当我们运行脚本的时候,当摄像机的距离超过Vector3.Distance(transform.position, Sphere.position);立方体虽然在摄像机的视野范围之内,但是仍然不可见。只有小于这个距离的时候才可以观察到。大家可以自行的测试。
二:遮挡剔除(Occlusion Culling)
当场景中包含大量的模型的时候,势必会造成渲染效率的降低(即帧速率FPS的降低)。如果使用遮挡剔除的技术之后,可以使那么被阻挡的物体不被渲染。从而达到提高渲染效率的目的。
基本的原理:遮挡剔除的基本的原理是:在场景的空间中创建一个遮挡区域,该遮挡区域有单元格(Cell)组成,每个单元格构成整个场景遮挡区域的一部分。这些单元格会把整个的场景拆分成对个部分。当摄像机能够看到该单元格的时候,表示该单元格的物体就会被渲染出来。而被其他的单元格挡住的不被摄像机看到的单元格中的物体将不会被渲染。
(1):我们先来构造一个高楼林立的场景(有点丑,大家见谅)。如图所示:
(2):除了把摄像机、直线光、地面,其余的把层级视图中的所有的游戏对象都标记为“遮挡静态”(Occluder Static/Occludee Static),如图所示:
特别提示:当我们选择一个包含多个子对象的父对象,标记为“静态遮挡”的时候,会出现一个弹出窗口,我们一般点击选择“Yes change children”就可以了。
(3):执行命名菜单:Windows——>"Occlusion Culling",弹出“遮挡剔除”面板,然后点击“Bake”按钮,进行烘培。如图所示:
(4):这时候当我们移动摄像机的时候,如果摄像机低头“看”地面时,整个场景中的游戏对象都无须进行渲染。如果所示:
总结:关于遮挡剔除,Unity还提供了“Occlusion Area”、“Occlusion Portal”但是在实际的项目中实用价值不高,顾再次不做详细的介绍。