Unity场景模型优化技术--LOD和OcclusionCulling

LOD和Occlusion Culling
Lod和遮挡剔除。
Occlusion Culling:Occlusion Culling 技术是指当一个物体被其他物体遮挡住而相对当前摄像机为不可见时,可以不对其进行渲染。遮挡剔除操作在Unity引擎中并不是自动进行的,这时因为在很多情况下离摄像机较远的物体先被渲染,而靠近摄像机的物体后被渲染,从而覆盖了先前渲染的物体(这被称为重复渲染overdraw)。遮挡剔除不同于视椎体剔除(Frustum Culling)视椎体剔除只是不渲染摄像机视椎范围之外的物体,而被其他物体遮挡但依然在视椎范围之内的物体则不会被剔除。(当使用遮挡剔除功能时,视椎体剔除依然有效)
遮挡剔除:在我们的场景中,如果物体1在Camera渲染中遮挡了另一个物体2,那物体2就不会再Camera中进行渲染,虽然物体2没有在Camera中进行渲染但是在整个游戏场景中这个物体同样存在。为了优化效率,这里就需要使用遮挡剔除。
Lod: 如果一个物体离我们的Camera很远,我们自然就看不见这个物体(或者只能看见一个“小点”)。但是这个物体在场景中仍然会根据它的顶点结构进行渲染并消耗性能。这时候为了优化,如果它离我们的Camera距离很远,我们就不需要对它进行渲染,也就是Lod。
一、Occlusion Culling(遮挡剔除)
1.遮挡剔除功能在Unity中使用Occlusion Culling(遮挡剔除)组件来进行实现
首先我们需要对需要进行遮挡以及被遮挡的物体进行烘焙。
在烘焙的时候,我们需要对遮挡的物体和被遮挡的物体进行选择不同的情况不同的解决方案。(比如一个玻璃物体遮挡住了另一个物体这时我们也应该对玻璃后的物体进行渲染)
这里不考虑这种情况,直接进行烘焙。


 
2.烘焙完成以后,这里我们将Occlusion Culling的属性从Edit改为Visualize来查看效果。


 
3.这时无法再Camera中渲染出来的物体,在场景中也不会进行渲染。


 
二、LOD技术
LOD: 即Levels of Detail的简称,意为多细节层次。LOD技术指根据物体模型的节点在显示环境中 所处的位置 和重要度, 决定物体渲染的资源分配 ,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。
在Unity场景中,根据摄像机与模型的距离,来决定显示哪一个模型,一般距离近的时候显示高精度多细节模型,距离远的时候显示低精度低细节模型。
通过lod技术,可以轻松实现
1.不同相机的距离切换不同精度的模型;
2.可以在不同相机的距离决定模型是否渲染。
在lod技术基础上,打破静态的限制,升级动态解决方案
3.动态解决方案(LOD)
4.动态解决方案(遮挡剔除)
废话不多说,上案例 (lod组件: LOD Group):
1.不同相机的距离切换不同精度的模型。
1.1先准备3个模型(不同精度的,lz这里为了突出显示用3个不同颜色代替)。



 
1.2然后创建一个空物体,把这三个模型放在空物体下,并给空物体添加Lod组件:LOD Group

LOD Group组件中,LOD0、LOD1...到Culled之间百分比可以根据自己要求拖动调整。
点击LOD0然后在点击Add添加不同的模型。
1.3添加完成后,可以移动组件LOD Group中的相机在Scene面板中查看,也可以运行起来通过移动相机在Game视图中查看。


 
2.可以在不同相机的距离决定模型是否渲染。
Lod功能,unity内置的组件也会为我们提供了一套解决方案。(LOD Group组件)
2.1 首先我们先创建一个小球,可以看见camera已经距离很远,此时只能看见一个小点。但它仍然是场景中进行了渲染。
实现LOD优化,为它添加LOD Group组件。


 
其中LOD 0,LOD 1分别为Camera距离这个球的距离区域划分。
2.2 我们可以在这些相对距离区域中选择是否要在这个距离对小球渲染。


 
2.3 我们在需要对小球进行渲染的距离区域中添加小球的Mesh网格信息,这样在这个Camera到小球的距离内,场景就是对小球进行渲染。


 
2.4 到我们拖到LOD2的距离区域后段时,这时场景会认为小球在距离Camera这么远的距离时不需要对小球进行渲染了,则小球就没有被渲染。(只是取消了小球的渲染,并不是enable等于false,所以小球的网格信息仍然存在。)


 
2.5 这时如果你觉得这个距离小球还需要被渲染,你就通过Add为这个距离区域添加上小球的render。小球会被渲染出来。



 
2.6 如果你对这些距离区域都不是你自己想要的,你同样可以对区域进行编辑并创建新的距离区域。



 
2.7 运行游戏来观察效果,当小球具体我们Camera超过我们的渲染的距离区域时,小球就不会进行渲染。(尽管小球仍然在我们Camera的视野范围之内)


 
以上方案的缺陷。
以上完成的操作都是静态的物体,但是在我们的实际项目开发中,NPC,Monster,建筑物等都是动态生成的。这种情况肯定就无法烘焙成静态的。
3.动态解决方案(LOD)
这时我们使用脚本来控制。而LOD的核心也就是在距离远的时候将小球的MeshRender组件失活我们根据这个核心点去编写代码。
3.1 为我们的Camera添加一个LODAndOcclusionController的脚本。
完成简单的动态LOD功能。
脚本源码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LODAndOcclusionController : MonoBehaviour {

    public GameObject sphere;
    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        if (Vector3.Distance (this.transform.position, sphere.transform.position) > 5f) {
            sphere.GetComponent ().enabled = false;
        } else {
            sphere.GetComponent ().enabled = true;
        }
    }
}

3.2 将小球挂载到脚本上(sphere)

3.3 场景测试 -- 这时我们可以发现当Camera和小球的距离超过5米的时候,小球则不会进行渲染。小球是动态运动的也同样没有关系。
相机移动效果:

小球移动效果:

4.动态解决方案(遮挡剔除)
4.1 使用Ray射线来进行判断。
4.2 我们将所有需要进行遮罩剔除的物体添加Tag为Occlusion。


 
4.2 并为我们的Camera添加脚本。

代码贴上:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class OcclusionController : MonoBehaviour {
    private GameObject[] occlusionGameObjects;
    // Use this for initialization
    void Start () {
        occlusionGameObjects = GameObject.FindGameObjectsWithTag ("Occlusion");
    }

    // Update is called once per frame
    void Update () {
        foreach (GameObject item in occlusionGameObjects) {
        Ray ray = new Ray (this.transform.position, (item.transform.position -             transform.position));
        RaycastHit hit;
        Debug.DrawLine (transform.position, item.transform.position - transform.position, Color.red);
            if (Physics.Raycast (ray, out hit)) {
                if (hit.transform.gameObject == item) {
                    item.GetComponent ().enabled = true;
                } else {
                item.GetComponent ().enabled = false;
                }
            }
        }
    }
}

测试结果
遮挡前:


 
遮挡后:


 
结论:
我们的LOD以及Occlusion,都是基于GameObject的MeshRender组件来实现的。只有掌握好核心点,不让它们进行渲染,这样减少了Draw Call自然就优化了性能。(主要为什么是让MeshRender组件失活,因为我们直接把整个游戏对象都失活了,那所有的碰撞信息也全部都会失效。)
关于优化:
① 首先优化DrawCall
② 优化顶点数、面数
LOD优点:减少顶点数、面数(为了显卡)
LOD缺点:① 增加CPU计算 ② 内存占用率大(因为有3个物体,Hierarchy中的每个物体都占一块内存)
手游不需要,虚拟现实、PC需要 ( •̀ ω •́ )✧
存在面数较高物体,且有时近有时远的时候用

猜你喜欢

转载自blog.csdn.net/u013774978/article/details/129941497