原理

游戏中的元素非常多,但是摄像机能看到的内容是有限的,并且有些元素会被另外一些元素挡住,例如城墙一类的,城墙后面的元素就会被它挡住。如果不进行处理的话,这些元素也会带来一定的开销,此时可以使用遮挡剔除技术来剔除掉这些被挡住的元素,只动态保留摄像机能看到的内容。

遮挡剔除

unity遮挡shader unity遮挡剔除原理_unity

遮挡被遮挡

属性

描述

Occluder Static

在遮挡剔除系统中,将游戏对象标记为静态遮挡物

Occludee Static

在遮挡剔除系统中,将游戏对象标记为静态被遮挡物

Object

筛选器

描述

All

全部

Renderers

在 Hierarchy 窗口或 Scene 视图中选择一个渲染器,即可在 Occlusion Culling 窗口中查看和更改渲染器的遮挡剔除设置

Occlusion Areas

在 Hierarchy 窗口或 Scene 视图中选择一个遮挡区域, 然后在 Occlusion Culling 窗口中查看和更改遮挡区域的 Is View Volume 设置

Bake

参数

描述

Smallest Occluder

可以遮挡其他游戏对象的最小游戏对象的大小(以米为单位)。通常,要使文件最小且烘焙时间最短,应选择在场景中产生良好结果的最大值。

Smallest Hole

摄像机可以看到的最小间隙的直径(以米为单位)。通常,要使文件最小且烘焙时间最短,应选择在场景中产生良好结果的最大值。

Backface Threshold

如果需要减小烘焙数据的大小,Unity 可以在烘焙时对场景进行采样,并排除场景中可见遮挡物几何体所含背面超过给定百分比的部分。背面百分比很高的区域可能在几何体的下方或内部,因此不太可能是在运行时摄像机所在的某个位置。默认值 100 表示绝不会从数据中删除区域。值越小,产生的文件就越小,但可能会导致视觉失真。

Occlusion Culling 弹出窗口有两种模式:EditVisualization

Edit

设置

描述

View Volumes

启用此选项后,Scene 视图将包含蓝线,这些蓝线显示遮挡剔除数据中的单元格。单元格大小受 Smallest Occluder 设置的影响:值越小,产生的单元格越多且越小,从而使精度提高并且文件增大

Visualization

Visualize 模式可让您从给定摄像机的视角预览遮挡剔除的结果。如果选择了某个摄像机,则预览与该摄像机相关。否则,预览与您在 Visualize 模式下选择的最后一个摄像机相关。

设置

描述

Camera Volumes

启用此选项后,您会看到黄线,黄线指示 Unity 为其生成遮挡剔除数据的场景区域。这取决于场景几何体以及在场景中使用 Occlusion Areas 选项定义的任何视图体积 (View Volumes)。当摄像机在黄线之外时,Unity 不会执行遮挡剔除。还可以看到灰线,这些灰线指示摄像机当前位置所对应的遮挡剔除数据中的单元格以及当前单元格中的细分。Smallest Hole 设置定义了单元格内细分的最小大小:值越小,每个单元格产生的细分越多且越小,从而使精度提高并且文件增大。

Visibility Lines

启用此选项后,您会看到绿线,这些绿线指示当前选择的摄像机可以看到的内容。

Portals

启用此选项后,您可以看到一些线代表遮挡数据中单元格之间的连接。当前可见的入口是当前所选摄像机可以看到的入口

Occlusion Area

unity遮挡shader unity遮挡剔除原理_unity_02

unity遮挡shader unity遮挡剔除原理_unity遮挡shader_03

遮挡区域,在大型的场景中如未创建遮挡区域游戏组件时,Unity会自动在烘焙时候进行创建,可能产生大量不必要数据。
所以这里建议手动创建遮挡区域 (Occlusion Areas) 放置在场景中,从而定义摄像机可能处于的区域的视图体积

设置

描述

Is View Volume

启用:Occlusion Area 将定义视图体积。 禁用:Occlusion Area 不会定义视图体积。 必须启用此属性才能使 Occlusion Area 生效。

遮挡与被遮挡事件

当发生遮挡剔除时,Unity会自动调用 gameObject.SetActive(false) 方法,可以使用以下方法进行监听

unity遮挡shader unity遮挡剔除原理_游戏引擎_04

using UnityEngine;

public class OcclusionListener : MonoBehaviour
{
    // 隐藏状态
    private void OnBecameInvisible()
    {
        Debug.Log($"隐藏 ---> {}");
    }

    // 显示状态
    private void OnBecameVisible()
    {
        Debug.Log($"显示 ---> {}");
    }

}
// 相机脚本
using UnityEngine;

public class RotationCamera : MonoBehaviour
{
    public float speed = 10f;

    private void FixedUpdate()
    {
        float h = Input.GetAxis("Horizontal");
        if (h < 0)
            transform.Rotate(Vector3.down * Time.deltaTime * speed, Space.Self);
        else if (h > 0)
            transform.Rotate(Vector3.up * Time.deltaTime * speed, Space.Self);
    }
}