All Houdini Unreal Engine 4

Houdini 大地形导入 Unreal 的两种方法

 
 

  • 仅仅修改Houdini文件即可实现的方法

 
 

网络上很多文章都有说明,如果我们在Houdini这一测使用其提供的TileSplit节点的时候,是可以在Unreal里面一次性生成多张地图,其效果如下:

但是这里存在两个问题:

  • 这不是正确的Unreal里面使用流式加载地形的正确方式。
  • 不同地形之间的接缝是很难消除的,因为他们隶属于不同的高度图,高度图生成地形还要基于采样生成模型,这个过程对于不同的高度图之间,他们是不会考虑相互影响的,因此总会存在下列情况。

 
 

因此从Unreal的角度出发,如何来实现大地形。Unreal默认就提供了可以根据多张切好的高度图来生成大地形的工具,我们可以借用这个工具,让Houdini直接输出切好的地形高度图即可实现。

 
 

Houdini这一侧的做法,如下图所示,如要注意的如下:

  • 采用heightfield_output节点作为输出
  • 保证输出的图片的格式是Unreal可以读取的高度图格式,也就是单通道的16比特浮点数据
  • 对高度图做切分,但是一定要保证切分的高度图之间的TilePverlap数值为1

得到的文件效果图,注意这里的自动命名正好是Unreal可识别的命名方式。

 
 

 
 

Unreal这一侧的做法如下所示,主要要注意的是:

  • 首先要保存地图,然后开启World Composition功能

  • 然后即可采用Import Tiled Landscape功能来实现生成流式加载的大地形的功能,功能入口如下图

  • 功能按钮弹出的对话框里面,选择文件,一次选中所有的我们期望生成地形的高度图,然后调整相关参数,最后点击生成即可实现。

 
 

效果:

 
 

 
 

 
 

 
 

 
 

 
 

  • 修改Unreal源码,兼容当前的HDA的方法

 
 

 
 

上一种方法固然简单,不需要额外的开发即可使用,但是存在几个问题:

  • 所有的HDA的输出都必须作出修改,使得可以生成文件,才可如上使用
  • 上述方法无法保留地形的图层信息

 
 

同时我们可以发现,地形HDA最终导入Houdini,会生成一个挂载在HDA下面的landscape对象。那么我们是否可以使用这个对象的信息,来切割大地形呢?

答案当然是可以的。

 
 

这边我参考了 https://zhuanlan.zhihu.com/p/68927318 这位大哥的实现,思路基本类似。

 
 

最终我们实现的是,在原来HDA的地形存在的Bake按钮的边上,实现一个Tiled Bake的按钮,用户点击这个按钮的时候,弹出一些选项面板,用户点击确定bake即可实现切割地形生成子关卡的Bake。

首先Houdini导出一张由内容量的地形:

然后你可以使用我们新添加的按钮:

然后弹出对话框设置切多少份:

最后就会生成切好的地形:

 
 

 
 

 
 

 
 

Unreal修改的一些注意事项:

  • 在Bake这个按钮的边上,添加Tiled Bake按钮

    这个函数里面要做的事情:

    Landscape要脱离原来的HDA,作为场景的一个独立个体,就是原来Bake的功能:

    检查World Composition状态

    获取HoudiniEngine插件生成的Landscape对象,传给后续的处理模块作为输入。

     
     

  • Tiled Bake按钮实现的功能,类似于前面我们提到的Import Tiled Landscape的功能,只是这边不是通过Import实现,而是通过Bake实现,因此我们可以仿照Import Tiled Landscape功能的实现函数实现 。

    因此首先要开放这个功能给上面的HoudiniEngine插件用:

    Public: virtual void BakeHeightmapTiled(UWorld* InWorld, class ALandscapeProxy* InLandscape);

    这个函数则是去调用真正的功能实现函数:

 
 

  • BakeTiledLandscape_Executed 作为功能实现函数,做了如下事情

    首先是唤起一个窗口,用作用户设置,这个窗口可以参考STiledLandcapeImportDlg来实现,独立建一个类。下面是调用代码:

    然后是根据用户的输入,去划分地形,最后调用MoveToLevel函数来实现数据按地形划分。这里我们通过NewWorld来借用其创建的map作为子level。

    MoveToLevel函数里面的实现,基本思路就是首先根据前面已经划分好的区域,我们选择得到哪些ULandscapeComponent是属于这块区域的,然后我们需要将这块区域的这些组件的proxy设置为新的proxy,意思就是改变他们的所属地形,除了LandscapeComponents,还需要处理CollisionComponentsWeightmapUsagemap。这里面还涉及大量的关联贴图数据的分割保存,比如这边拷贝高度数据的部分由SplitHeightmap这个函数完成。

    下面是组件拷贝的代码,如果新的地图的stream如果以来的数据没有都存到这个levelproxy里面的话,就会无法保存。

     
     

     
     

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

Leave a Reply

Your email address will not be published. Required fields are marked *