在(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析这篇博客大致介绍HISM组件从游戏线程到渲染线程的重建KD-Tree和剔除并提交DrawCall逻辑,但是没有分析渲染层的大致数据结构和实现.

FHierarchicalStaticMeshSceneProxy的相关数据结构

可以看出FHierarchicalStaticMeshSceneProxy 实际存储Instance数组数据来自于FInstancedStaticMeshSceneProxy

FHierarchicalStaticMeshSceneProxy只是以FClusterNode构建了Kd-Tree, 存储以及管理的是以KD-Tree形式的Instance索引. 具体怎么管理,可以看上一篇HISM的介绍文章。

FInstancedStaticMeshRenderData

这个数据结构是HISMProxy和ISMProxy的核心数据类, 负责了StaticVertexBuffer, InstanceVertexBuffer(每个实例的Transform) 和VertexFactory(FInstancedStaticMeshVertexFactory)直接的绑定。

VertexBuffer

来自于UStaticMesh的渲染数据

InstanceBuffer

来自于ISM组件管理的FPerInstanceRenderData

FPerInstanceRenderData专门使用了FStaticMeshInstanceBuffer来管理渲染线程的InstanceVertexBuffer资源。

FInstancedStaticMeshVertexFactory

直接继承FLocalVertexFactory, 主要是改写了顶点格式, 因为Instance批渲染需要在VertexShader读取InstanceData(WorldTranform等),但是Instance批渲染一般有两种实现方式:

第一种是InstanceData直接作为VertexBuffer的一部分,顶点可以直接获取到其所在Instance的WorldTranform, 参考DirectX 11 学习笔记-Part2-1【Instancing】

第二种是Instance数据作为Buffer独立创建,顶点数据只包含InstanceId, 每次取InstanceData得用InstanceId从InstanceBuffer中取,这种比较多出现在GPU Driven渲染管线里,GPU Driven Rendering大量使用各种Buffer,直接读Buffer, 可以比较好的避开CPU readback, 参考Unity实现GPU Cull渲染

在UE引擎渲染中叫第二种方式叫手动顶点获取(MANUAL_VERTEX_FETCH)

目前UE5 Mobile端(无论是OpenEs 还是Vulkan)都不支持MANUAL_VERTEX_FETCH,在PC端延迟渲染是GPU Driven Cull Instance实现,默认支持MANUAL_VERTEX_FETCH。(题外话: Mobile端 Instance 批渲染目前还未实现GPU Driven的DrawInstancedIndirect,有兴趣的可以研究下UE5 PC端延迟渲染管线的GPUScene, 实现了完整的Instance GPU Cull和DrawInstancedIndirect。总结就是UE5 Mobile是完全基于CPU剔除的DrawInstance, UE5 PC端是基于CPU剔除和GPU剔除的DrawInstancedIndirect)

LocalVertexFactory.ush的InstanceData获取

代码实现,MANUAL_VERTEX_FETCH为false编译后可以看出是通过InstanceVertexBuffer来获取InstanceData. 如下所示: