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
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个能合并的物体才会去合。
源码修改
- 如果是HISM,则把HISM内的Instance给重新加入到合批中
这里还把之前的注释掉了,因为我们之前的 HISM 的 Actor 类型就是一个 AActor,会与设置中最后合批的类型 ActorClassToUse 相同,我们不希望被跳过:
- UE源码这里没有指定初始值,经过测试这里的 HLODVolume 可能会沿用之前的 HLODVolume 值,导致最后合批不严格按照 HLODVolume 划分。 我在这里补上了初始值。
- 组织方式修改:原来ue的功能会把所有不同的mesh都合成一个actor,一种mesh挂一个 ISM 或者 HISM,我们应该是希望一种mesh一个actor
调试一下是这样的:
核心代码在 FMeshMergeUtilities::MergeComponentsToInstances 的:
我们这里把 MergedActor 从类 FActorEntry 转移到 FComponentEntry 中了,就完成了我们想要的效果。
补充说明
可能会改到相关材质资产,比如增加flag bUsedWithInstancedStaticMeshes:
一键生成碰撞
打开一个 Static Mesh 的资产,在 Collision 这里,如果有 Primitives,则是简单碰撞,一般美术自己编辑的碰撞信息 最后也会进这里面:
但是如果一个物体没有简单碰撞,UE 则会自动生成一个复杂碰撞(即三角面的碰撞体):
这样太费了,我们希望做的是遍历场景所有 Mesh,检查是否有简单碰撞,若没有则自动生成。UE 是有自动生成接口的:
我们希望生成的是 DOP 的或者 Convex 的。
相关代码
对应的碰撞信息位于:StaticMesh->GetBodySetup()->AggGeom.GetElementCount()