[ue4] HISM 大规模植被渲染解决方案

Posted ZJU_fish1996

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ue4] HISM 大规模植被渲染解决方案相关的知识,希望对你有一定的参考价值。

        HISM,即HierarchicalInstancedStaticMesh,是ue4中针对类似植被这样大规模重复物件渲染提供的一种解决方案。本文仅作为HISM设计的导读,具体细节需参照源码的实现。

ISM

        在讨论HISM之前,我们先来看一下ISM,即InstancedStaticMesh。简单来说它就是ue4提供的实例化渲染,通过Instance,绘制n个相同的物体,原来需要n次drawcall,现在只需要一次就可以了(更多的细节可以猛戳这里)。

        想象一下,如果我们想要渲染一束花,一盒鸡蛋,这看起来是一个非常不错的解决方案。但是,如果我们要渲染一望无际的植被,就会出现以下这些问题:

        (1) 视野中只会出现部分植物,但绘制时却需要提交整个植被;

        (2) 我们难以控制远、中、近景的精度(LOD);

        一个比较简单的思路是,可以把植被拆分成多个部分来管理,进行选择性的drawcall。

HISM

        为了解决上面提到的问题,ue4提供了HISM的解决方案,H对应的就是层级的意思。它的思路本质上也是把植被拆分,只不过更加复杂一些,针对每个StaticMesh,构建一个ClusterTree的树状结构来管理植被。它仅在创建物体时自动构造一次,因此只适用于静态的类植被的物体。

        首先,先不管这棵树的具体结构,我们来考虑一个问题:如何将instance物体拆分为多个部分,并分段提交?

        instance物体对应了一个instance buffer,它按顺序存储了每实例的structure数据,比如transform信息。如果我们希望将原instance物体拆分为k份,我们确实可以重新分配k个instance buffer,不过还有更加简单的方法。

        在绘制instance时,图形API提供了相关的接口,可以指定instancebuffer的起始位置和偏移值,以及设定实例数量,来控制最终绘制的实例。也就是说,我们只需要k个instance buffer的起始位置和偏移值,就能将原有的实例物体拆分为k部分。这样做的好处在于,我们不需要重新分配instance buffer。

将一个instance buffer拆分为多块,记录有效区间(蓝色部分)的起始位置和偏移值

        通过这样的方式,我们可以以一种较为粗糙的细粒度来控制植被的剔除以及LOD的切换。 

ClusterTree

        ClusterTree是一棵多叉树,它的每个节点包含了首尾Instance Id,对应一段区间。将父节点的区间切割后生成多个子节点。

        为了控制树的生成形状,我们可以设定预设剔除的粒度(越小剔除越精细)、预设至少生成多少实例等数据,ue4会根据这些设定计算出合适的BranchingFactor,作为当前节点是否要继续划分的依据。

        ClusterTree的构建方式:对所有实例在最大轴向上排序,然后一分为二,再对每个子区间继续划分。下图描述了这一过程:

        通过递归的划分,我们得到了多个子区间,但我们并没有得到一棵树。为了构建树,我们需要重复上图的递归过程,先构建叶节点,再将叶节点视为多个大的实例,构建其父节点,自底向上完成整个过程。

剔除

        在ue4的几何体绘制管线中,存在静态和动态两个流程,最终的绘制指令由MeshCommand封装。

        对于静态绘制而言,会在物体创建并添加到场景时构建StaticMeshBatch,并缓存下来,除非有必要才会重新生成MeshBatch。

        而对于动态绘制物体而言,需要每帧生成MeshBatch,再基于MeshBatch生成最终的MeshCommand,因为每帧的MeshBatch信息可能发生变化。

        由于镜头的转换后,我们需要绘制的植被部分可能会发生变化,因此在使用HISM后,就必须走动态绘制的流程。

        剔除的过程在InitViews中进行,这一过程实际上完成了两个操作,一个是可见性计算,此外是收集对应的MeshBatch并生成MeshCommand。HISM的剔除不在常规的可见性计算流程中,而是在收集动态MeshBatch流程中完成。

        在生成MeshBatch时,从ClusterTree根节点开始计算节点对应的包围盒是否在视锥体内,如果在则继续查询子节点。将可见节点对应的首尾instance id记录到数组中(必要时合并连续区间),得到多段首尾instance id。

        仔细观察MeshBatch的结构,会发现它包含了一个Element的数组,但是一般静态物体只会用到一个Element。而对于HISM而言,则是一段区间对应一个Element,这个结构似乎就是专门为了兼容HISM这类数据的提交而实现的。

        当我们把HISM的数据拆分为k段提交后,我们将在MeshBatch下得到k个Element,它们将进行k次drawcall。这里就存在一个取舍问题:拆分得越精细,意味着剔除越精细,但drawcall有可能提升;反之剔除越粗糙,drawcall将降低。

LOD

        LOD也就是根据相机到物体距离的远近选择不同精度模型(对植被而言,最远处切换为公告牌)。在剔除过程中计算视锥体和节点对应的包围盒相交的过程中,我们也同时计算包围盒中心到相机的距离,并决定这一区间的绘制层级,然后将首尾instance id记录到对应LOD层级的数组中。

以上是关于[ue4] HISM 大规模植被渲染解决方案的主要内容,如果未能解决你的问题,请参考以下文章

Houdini技术体系 过程化地形系统:Far Cry5的植被系统分析

UE4搭建场景与特效文档—地形水体植被雨雾效果

8 UE4添加和设置植被石头

UE4-材质法线强度调整法线贴图混合自定义材质函数材质边缘过渡植被动态效果

ArcGIS制图技巧系列还原真实的植被

ArcMap制图技巧之还原真实植被