在 (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. 如下所示: