(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

这篇具有很好参考价值的文章主要介绍了(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

游戏开发中的植被管理一直是个棘手的问题,因为植被数量庞大,对于剔除(CPU)和渲染(GPU)都存在很大的压力。

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

UE4的植被有一套独特的管理方式, 是基于 UHierarchicalInstancedStaticMeshComponent组件实现了植被的视椎体剔除和合批渲染。

UHierarchicalInstancedStaticMeshComponent原理分析

HISM类关系

UFoliageInstancedStaticMeshComponent下面简称FSM.

UHierarchicalInstancedStaticMeshComponent下面简称HISM.

InstancedStaticMeshComponent下面简称ISM.

在UE4里FSM,HISM,ISM是UE4最常用的对网格Instance合批渲染组件.

这三个组件的关系类图如下所示

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

FSM在UE4进行植被编辑模式的时候产生(挂载在AFoliageActor上).而HISM得手动进行AddInstance的合批, 由于FSM的CPU剔除和GPU合批方式基本沿用HISM,而ISM是最基本的粗暴合批,没有精妙的CPU剔除, 所以本文重点分析HISM。

CPU剔除实例

HISM管理着同一个StaticMesh的大量实例, 假设实例数量高达1万个,当然在提交drawcall前并非每个Instance都得被渲染,所以得进行视锥体剔除,按照传统的CPU方式,暴力进行对每一个实例视锥体剔除,CPU压力很大。

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

暴力遍历Instance进行视锥体求交对CPU性能压力很大,往往是瓶颈的所在,因此场景管理上出现了各种空间管理结构,加速CPU的实例剔除。 典型的有BSP(二叉空间树),Octree(八叉树), QuadTree(四叉树)等等。UE4的HISM针对大量Instance也有独特的空间管结构,我称其为基于Cluster的N叉树。空间结构和KD树有些类似(Build),剔除(Cull)的过程则和二叉,四叉树等类似,都是从大空间开始剔除,依次递归往子空间进行剔除,最终得到和视锥体相交的所有Instance.

HISM的空间结构和构建过程

上面我简称HISM的空间结构为N叉树,是因为这个N是可控的,随着某些因素的影响变化(比如StaticMesh的顶点数量,叶子节点最大顶点数量等等)

HISM的N叉树原理

首先说下HISM的N叉树的数据结构是用索引数组而非链表构成的。

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

首先TArray<FInstancedStaticMeshInstanceData> PerInstanceSMData存在了所有实例的WorldTransform, 凭每个Instance在数组的索引我们就能在GPU上获取相应的Transfrom进行VertexShader从而合批渲染。

 TArray<FClusterNode> ClusterTree存储了整个N叉树的结构。FClusterNode代表了每一个树的节点。

FClusterNode的FirstChild指当前节点在数组ClusterTree的第一个子节点的索引,而LastChild代表当前节点在数组ClusterTree的最后一个子节点的索引,也就是说当前节点存在

(LastChild - FirstChild + 1)子节点,而当前节点的BoundMax, BoundMin指的是当前节点包含的所有实例在世界空间形成的BoundBox,而当前节点的FirstInstance和LastInstance指当前节点包含所有实例的第一个Instance在PerInstanceSMData的索引,而LastInstance指的是所有实例的最后一个Instance在PerInstanceSMData的索引,也就是说当前节点拥有实例数量等于(LastInstance - FirstInstance  + 1). 当前节点和子节点各种变量的关系如图下所示:

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 可以这样说, 当前节点的所有子节点所有的Instance加起来就等于当前节点所拥有的Instance, 当前节点所有Instance形成的BoundBox和其所有子节点的Instance形成的BoundBox涵盖的范围总和是一样的。说到这里,熟悉空间剔除结构的人看到这里大体应该明白了HISM N叉树的基本原理,也就是大空间包含数个小空间,大空间的BoundBox如果与视锥体相交, 那遍历其所有子空间的BoundBox和视锥体求交,反之大空间不与视锥体相交,则其所有子空间都不可能与视锥体相交,整个过程都在递归进行。可以大致参考下地形渲染之四叉树(QuadTree) 来理解。

唯一的问题在于HISM的N叉树具体是怎么构建的,我简单总结,HISM的N叉树结构和构建过程和KD树有些类似

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 HISM的N叉树构建

第一步----构建叶子节点:  首先生成N叉树的所有叶子节点,覆盖了所有Instance的Index范围, 并且每个节点的Index范围不重叠。

比如我们存在90个实例,并假设一个FClusterNode叶子最多容纳20个实例, 则生成5个叶子节点:

[0, 19], [20, 39], [40, 59], [60, 79],[80, 90], 当然实际上不会分得那么均匀.

这个生成叶子节点的过程是怎么发生的:

假设我们有M个实例:

(1)将所有Instance的Transform组成一个数组为TArray<FTransfrom> Positions; 而所有Instance的索引则是为TArray<Index> InstanceIndexs;

(2)对[0, M-1] 口模型划分数量划分

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

如果当前范围实例总数量小于等于BranchingFactor,则递归结束, 形成一个叶子节点

BranchingFactor = clamp(叶子节点可以容纳最大顶点数量 / 实例StaticMesh 0级Lod的顶点数量, 1, 1024)

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 可以看出叶子节点可以容纳最大顶点数量的是个可控的量

如果当前范围实例总数量大于BranchingFactor ,对所有实例形成的BoundBox的最长轴(X或者Y或者Z)代表的Position分量进行距离排序,如下面X轴就是最长轴

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

然后对排序后进行数量上二分切分(类似二分查找),回到第二步的初始一直递归下去.

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 最后所有递归结束,形成 Q个叶子节点FClusterNode, 这Q个叶子节点各自代表的InstanceIndex范围不存在重叠,并且总和数量刚好 = 总实例数量M

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

当然递归二分法下得到的InstanceIndex的分布范围不会这么均匀, 我这里只是一个假设的例子

第二步----由叶子节点从下往上构建上层树节点直到根节点为止

第一步我们得到包含了全InstanceIndex范围的一些ClusterNode节点(看上面图所示), 下面我们进一步把这些ClusterNode都分为视为一个位置点, 位置点为一个ClusterNode内所有实例形成的BoundBox的中心点.  所以上面90个实例下得到5个Cluster, 就是5个位置点,一个位置点有些类似一个Instance实例

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 然后利用这些位置点类似上面的第一步那样进行二分递归划分,一直往上得到根节点,当然这里和第一步不太一样的是,节点自下往上过程得把子节点FCsluterNode的InstanceIndex范围归纳到母FClusterNode里,并且这里二分递归的终结递归因子和第一步形成叶子节点的终结递归因子不一样。这里的BranchingFactor 变为CVarFoliageSplitFactor,也是可控变量,默认情况是16,也就是每16个FClusterNode子节点才能形成一个母节点FClusterNode。

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 经过上面的步骤最终形成空间结构N叉树

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 HISM的Runtime剔除和渲染过程

 上面我们分析了在编辑器下HISM针对Instance的空间数据结构N叉树的构建过程。下面就是利用这个N叉树进行剔除的过程。首先从上面的N叉树构建过程,我们可以知道TArray<FClusterNode> 树节点数组的第一个节点为根节点,并且母节点和子节点的关系为:

母节点的InstanceIndex范围 = 所有子节点InstnceIndex范围总和

母节点的Instance构成的BoundBox = 所有子节点Instnce构成的BoundBox总和

因此整个剔除的过程是从根节点开始,自上而下进行剔除,遵循大空间BoungBox和视锥体相交, 则其子空间BoungBox也可能与视锥体相交, 反之大空间BoungBox和视锥体不相交,则子空间BoungBox绝对不可能与视锥体相交。和四叉树等等的剔除原理基本相似。

这个剔除过程发生在  FHierarchicalStaticMeshSceneProxy::GetDynamicMeshElements 提交MeshBatch之前

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 这里有个小细节的是剔除用视锥体是根据你在编辑器设置的CullDistance(UserData_AllInstances.EndCullDistance)计算出来,如下所示:

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 最终能渲染的ClusterNode的InstanceIndex的列表加入到一个分LOD管理的可渲染列表里

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

这里连续Index的Cluster节点会在AddRun后进行合并,比如[0, 31], [32, 50]合并成[0, 50] 

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

最后遍历可渲染列表的InstanceIndex分段,比如[0, 19] [30, 59]等等,来进行提交MeshBatch

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 这里的NumBatchs一般是1,而InstanceIndex分段数量意味着MeshBatch的Elements的数量,一个MeshBatchElement就是一次DrawIndexedInstance,  上面所说的N叉树的每个Cluster叶子节点代表可能存在的一次DrawIndexedInstance.

(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析

HISM的优缺点

优点

以Cluster为单位(每个Cluster存储的Instance数量可控),在CPU进行空间N叉树的剔除,总体上效率还可以。

缺点

因为是以Cluster为单位来剔除,假设一个簇刚还只有一个Instance在视锥体内,则造成Cluster其他Instance的绘制浪费,cluster粒度(包含Instanc总数)越大,绘制浪费越大。如果Cluster粒度小,绘制浪费比较小, 但是可能造成Cluster总数量提高,潜在的DrawCall(DrawIndexedInstance)数量也会提高。

参考资料

[1] HierarchicalInstancedStaticMeshComponent.h 和 HierarchicalInstancedStaticMesh.cpp文章来源地址https://www.toymoban.com/news/detail-488484.html

到了这里,关于(UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • UE4.27.2 Android开发环境配置

    虚幻官方文档链接:https://docs.unrealengine.com/4.27/zh-CN/SharingAndReleasing/Mobile/Android/AndroidSDKRequirements/ 虚幻4.27配置Android环境软件要求: 请确保UEAndroid平台组件已安装及Android Studio版本和VisualStudio版本符合要求。 下载链接:https://www.oracle.com/java/technologies/downloads/archive/ 我这里选择了

    2024年02月06日
    浏览(44)
  • 优麒麟ubuntukylin安装UE4.27.2

    在(国产)优麒麟 ubuntukylin Linux平台上编译测试安装虚幻引擎。 这里选择的是官方增强版 https://www.ubuntukylin.com/downloads/ 同样的可以选择对应的 Ubuntu22.04 LTS ,唯一的区别就是优麒麟做了一些定制,自带了一些国产应用及对系统作了一些配置(阿里源等等),省去一些麻烦。

    2024年01月23日
    浏览(44)
  • UE4.27 编译及打包HTML5相关资料

    https://docs.unrealengine.com/4.27/zh-CN/SharingAndReleasing/HTML5/GettingStarted/ UE4.27可以打包HTML5啦 https://github.com/Xi3Chen/UE4.27PackingH5DDoc https://blog.csdn.net/mrbaolong/article/details/131732174?spm=1001.2014.3001.5501

    2024年02月13日
    浏览(45)
  • VS2019编译UE4 4.27.2时出现编译报错

    完整的报错: 1.内部编译器错误。 UE4 D:UE4UnrealEngine-4.27.2-releaseEnginePluginsVirtualProductionRemoteControlSourceRemoteControlPrivateRemoteControlPreset.cpp 1870 2.严重性    代码    说明    项目    文件    行    禁止显示状态 错误    MSB3073    命令“....BuildBatchFilesRebuild.bat

    2024年02月14日
    浏览(45)
  • ue4.27空项目打包不卡ue5.1空项目打包运行卡的要命研究测试

    知乎上有人提问 lumen是如何做到不卡顿的,我却不以为然,我的显卡虽然算不上好显卡,但是也不至于独立显卡一个空项目都玩不起吧,打个cf,玩腾讯模拟器和平精英吃鸡肯定还是会很流畅的. 一个空项目都卡,怎么能说是我电脑配置问题呢??? 再来看提示 image.png image.png 反射设置的

    2023年04月21日
    浏览(65)
  • UE4.27.2 源码使用 VS2022 编译时出现的错误的解决方法

    Fstring 的获得指针的函数是 nodiscard 的,但是目前这个表达式是可能 discard 的 https://forums.unrealengine.com/t/build-from-source-fails-with-errors-c4834-and-msb3073/1266696/4 我遇到的错误如下 这应该是说明 10.0.22621.0 是不适用的 我在网上看到了别人的解决办法是只保留 Win 10 的 SDK,不要 Win 11 的

    2024年02月07日
    浏览(61)
  • 每日学术速递4.27

    Subjects: cs.CV 1. End-to-End Spatio-Temporal Action Localisation with Video Transformers 标题:使用视频转换器进行端到端时空动作定位 作者:Alexey Gritsenko, Xuehan Xiong, Josip Djolonga, Mostafa Dehghani, Chen Sun, Mario Lučić, Cordelia Schmid, Anurag Arnab 文章链接:https://arxiv.org/abs/2304.12160 摘要:         性

    2024年02月02日
    浏览(29)
  • 4.27 功率谱

     功率信号能量一定是无穷大的      1处解释,由于上述信号是截断信号,只有-T/2 ~ T/2有有效信号,因此有了1式        能量信号和能量密度构成傅里叶变换对 功率信号和功率密度构成傅里叶变换对 自相关函数和他的能量谱或者功率谱构成傅里叶变换对

    2024年02月11日
    浏览(27)
  • Ubuntu 20.04 + UE4.27 + Airsim + ROS 学习(2)(显卡rtx 4060+双系统)

    由于换了电脑,所以又重新配置了一下环境,所以想把自己在搭建过程中解决的一些问题进行分享。我是主体参考的Ubuntu18.04搭建AirSim+ROS仿真环境_airsim ros-CSDN博客小青蛙大佬的这篇,但是在顺着他的思路往下搭的时候自己也遇到了很多问题,所幸都解决了! 1. 首先是获取U

    2024年02月04日
    浏览(48)
  • Ubuntu20.04: UE4.27 中 Source Code 的编辑器下拉框没有 Rider选项

    最近想用 Rider 作为 UE4 开发的 IDE,但安装好 Rider 后,发现编辑器下拉框中没有 Rider 的选项,我检查了 UE4 的插件,发现 Rider Integration 插件已经安装且启用的。 环境:Ubuntu 20.04 + UE4.27 + Rider2023.2 在网上找了挺久,主要都是两种解决方案,有的人可以成功解决问题,但我尝试后

    2024年03月14日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包