All Unreal Engine 4

UE4 剔除 使用

官方文档

https://docs.unrealengine.com/zh-CN/Engine/Rendering/VisibilityCulling/index.html

可视性和遮挡剔除方法的大体思路是减少任意给定时刻的可见对象数量,从而达到优化性能的目的。

GPU-Driven 则是后面的趋势,可以全部采用Compute Shader来做OC,后面对于IB/VB进行合并处理。

 
 

方法

 
 

  1. 距离剔除

     
     

    每个Actor都有自己的绘制距离设置,可以使用 细节(Details) 面板进行设置。

     
     

    剔除距离体积(Cull Distance Volume):对于优化包含精细内部空间的大型室外关卡非常有用。当室内空间小到可被视为不重要时,可以剔除它们。
    用法:

    1. 将对象拖入场景

    1. 默认情况下属性上有两个 剔除距离(Cull Distance) 对;你可以将第一个剔除距离对作为要编辑的第一个条目,它的大小和距离都尚未设置,第二个剔除距离表示大于这个size的对象会免于剔除。

      剔除距离对可按需增减。

    使用建议:

    用一个剔除距离体积(Cull Distance Volume)覆盖整个关卡控制全局。

    设置剔除距离对时,可先从较大尺寸和距离开始,以了解你希望使用的上限和下限。

    剔除距离对组仅在低于个体Actor的 最大绘制距离 时才会被使用。

    某些Actor应永不被剔除距离体积(Cull Distance Volume)剔除,请使用该Actor的”细节(Details)”面板并禁用 允许剔除距离体积(Allow Cull Distance Volume)。

     
     

  2. 视椎剔除

     
     

    这部分全自动,不用处理,不用设置。

    在关卡视口中编辑时,选择 显示(Show)>高级(Advanced) 并启用 摄像机视锥(Camera Frustum),可以显示视图视锥。

     
     

  3. 遮挡剔除

     
     

  • 预计算可视性

    比较适合用于中小场景的性能优化,不适合大场景,这里忽略。

     
     

  • 硬件查询遮挡

    支持硬件查询遮挡的平台默认开启硬件查询遮挡是最好的方案。

    支持的平台包括iOS 上支持**ES 3.1**或更高版本和Android 上支持**Vulkan**的更高端移动设备。

    不支持硬件遮挡查询的设备可以禁用,方法是从 项目设置(Project Settings) 的 渲染(Rendering)>剔除(Culling)下面,取消选中 遮挡剔除(Occlusion Culling) 或在设备配置文件中设置: r.AllowOcclusionQueries=0

     
     

  • 软件查询遮挡

    优点就是可以在任何移动平台上使用。

     
     

    使用方法:

  1. 启用

    项目设置(Project Settings)>渲染(Rendering)>移动(Mobile) 中启用软件遮挡,并设置 支持软件遮挡剔除(Support Software Occlusion Culling)。

  2. 遮挡体设置

    在静态网格体编辑器中,使用 细节(Details) 面板,并将任何值设置为0或更大的值来启用 遮挡物网格体的LOD(LOD for Occluder Mesh)。

    默认为-1不进行遮挡。

  3. 调试

    使用控制台(`)通过 r.SO.VisualizeBuffer 1 启用软件遮挡可视化程序。

    使用命令 stat softwareocclusion 了解软件遮挡在关卡中的效果。

 
 

  • 循环遮挡

    仅用于VR,这里忽略。

 
 

性能调试

 
 

在控制台窗口中输入 stat initviews 可以调用统计信息窗口。

 
 

在编辑器中工作时,可以使用可视化命令检查Actor是否被遮挡。

r.VisualizeOccludedPrimitives 1 启用时,将围绕着任何被遮挡Actor绘制一个绿色边界框。

 
 

在编辑器中工作时,可以冻结关卡中Actor的渲染状态,这样可以在关卡视口中自由移动并检查遮挡结果。

从所需视图输入命令`FreezeRendering`

 
 

补充:地形是否参与遮挡剔除

 
 

这边还缺了个东西,就是将地形置于软件遮挡查询中,作为遮挡体。这个在文档里没有找到,但是在代码实现中貌似是有的。

我们来看Landscape的设置:

这里存在设置将哪一层的地形作为遮挡体,默认为第一层的LOD。

我们来代码里面找答案,这变量的定义:

这个值的引用在Landscape.cpp里面的实现都是在做数据拷贝,无意义。

唯一真正使用的地方是 ULandscapeComponent::GeneratePlatformVertexData 函数里面来生成occlusion mesh

这个函数的调用在 ULandscapeComponent 创建的时候发生,也就是创建landscape的时候会生成。

 
 

对比一下 staticmesh 里面的实现,其设置参数是

这个则是在mesh初始化的时候调用如下段落实现的生成遮挡体数据。

 
 

渲染的时候的处理

有一个重要标签:bUseAsOccluder 用来标记是否作为遮挡体。

对于地形,每个FLandscapeComponentSceneProxy对象里面生成网格对象的地方,会对这个值重新赋值,确认是否参与当作遮挡体。

也就是说landscape也是当做staticmesh来参与遮挡计算的。

 
 

实际测试

 
 

我们来实际测试一下遮挡。

建了一张测试场景,开启软件遮挡测试,红色的是设置为了遮挡体。

这遮挡剔除,冻结渲染后观察结果

开启遮挡剔除后,渲染效果