场景优化

ISM 与 HISM

继承链

ISM(Instanced Static Meshes)学过图形学的应该都不陌生,走的dc的api接口都有所区别。但是 ISM 需要所有的 Instance 都具有相同的 LOD,也就是说如果远处和近处都是用 ISM 一起渲染的,他们仍然要是一级LOD; 因此对于植被而言,通常覆盖范围较广,但是我们不可能远处和近处都用LOD0,因此又推出了 HISM(Hierarchical instanced static mesh),他把所有的 Instance 分簇,每一簇使用一级 LOD 层。

因此 HISM 可能每一簇是一个 dc,虽然多了 dc 以及组织结构的管理消耗,但是剔除会更加方便。

具体原理可以参考:

https://zhuanlan.zhihu.com/p/58963258

https://zhuanlan.zhihu.com/p/441958089

https://zhuanlan.zhihu.com/p/443809005

https://zhuanlan.zhihu.com/p/42949773

参考: https://www.intel.com/content/www/us/en/developer/articles/training/unreal-engine-4-optimization-tutorial-part-2.html

HLOD

官方文档: https://docs.unrealengine.com/5.0/zh-CN/hierarchical-level-of-detail-in-unreal-engine/

针对静态Mesh资产的功能,当模型处于远距离时,分层细节级别(HLOD)系统可以将多个静态网格体Actor合并成单个代理网格体和材质。 生成代理网格体是需要花时间的步骤,并且每次编辑完场景时,左上角可能有需要重新构建HLOD代理网格体的提示(有点像灯光一样,也是有重新构建灯光的步骤)。

Actor合并

一共有四种功能:Merge、Simplify、Batch、Approximate,每一种功能都可以在下面的 Merge Actors Settings 里面进行设置配置。

官方文档: https://docs.unrealengine.com/5.0/zh-CN/merging-actors-in-unreal-engine/

相关代码

UE 自带的这个合并功能,其中的 Batch 已经可以达到合批的功能了,其中注册到Editor的主要代码在:

void FLevelEditorContextMenuImpl::FillMergeActorsMenu(UToolMenu* Menu);

具体功能则是在 IMergeActorsTool 的接口 RunMergeFromSelection 中,可以参考做 Batch 的时候的调用栈:

做 Batch 的核心函数位于 MeshMergeUtilities.cpp:FMeshMergeUtilities::MergeComponentsToInstances

bReplaceSourceActors 可以指定是否要把之前的Actor替换为合并后的模型;其中在 FMeshInstancingSettings 可以指定是否依赖 HLOD Volume,可以指定 ISMComponentToUse (我们可以在这里换成 UHierarchicalInstancedStaticMeshComponent::StaticClass()),这个设置就和面板中的是对应起来的。

最后这个 Batch 功能就可以做到:对于选中的所有 Static Mesh 的 Actor,若能合并(材质、Mesh相同)则合并为一个 HISM,一个 HLOD Volumn 内的要单独合成一个;并且 我们可以指定最小的应该合并的数量(FMeshInstancingSettings-InstanceReplacementThreshold),指定为5就需要有5个能合并的物体才会去合。

源码修改

  1. 如果是HISM,则把HISM内的Instance给重新加入到合批中

这里还把之前的注释掉了,因为我们之前的 HISM 的 Actor 类型就是一个 AActor,会与设置中最后合批的类型 ActorClassToUse 相同,我们不希望被跳过:

  1. UE源码这里没有指定初始值,经过测试这里的 HLODVolume 可能会沿用之前的 HLODVolume 值,导致最后合批不严格按照 HLODVolume 划分。 我在这里补上了初始值。

  1. 组织方式修改:原来ue的功能会把所有不同的mesh都合成一个actor,一种mesh挂一个 ISM 或者 HISM,我们应该是希望一种mesh一个actor

UE默认的方式

调试一下是这样的:

核心代码在 FMeshMergeUtilities::MergeComponentsToInstances 的:

我们这里把 MergedActor 从类 FActorEntry 转移到 FComponentEntry 中了,就完成了我们想要的效果。

补充说明

可能会改到相关材质资产,比如增加flag bUsedWithInstancedStaticMeshes:

一键生成碰撞

打开一个 Static Mesh 的资产,在 Collision 这里,如果有 Primitives,则是简单碰撞,一般美术自己编辑的碰撞信息 最后也会进这里面:

但是如果一个物体没有简单碰撞,UE 则会自动生成一个复杂碰撞(即三角面的碰撞体):

简单碰撞与复杂碰撞

这样太费了,我们希望做的是遍历场景所有 Mesh,检查是否有简单碰撞,若没有则自动生成。UE 是有自动生成接口的:

我们希望生成的是 DOP 的或者 Convex 的。

相关代码

对应的碰撞信息位于:StaticMesh->GetBodySetup()->AggGeom.GetElementCount()

Licensed under CC BY-NC-SA 4.0