Export Height Fields to UE4

Over the past few posts, I talked about building Height Fields and went over how to convert Height Fields to polygon geometry so it can be used for other things like collisions in simulations or rendering after you apply a material to it. This post will go over some tips on how to export the Height Field terrain as an HDA (Houdini Digital Asset) and import it into Unreal Engine as a playable environment or game asset.

I often ranted about Houdini’s seamless integration with Height Fields and everything else in Houdini, but I think the HDA’s and Height Fields really tops it all. It’s so convenient to export the Height Field into Unreal Engine through a HDA.

Tricks

You might wonder why do another video on HDA. If you’ve been following my Youtube channel you’ll probably notice I already have a video on HDA to Unreal Engine, but that video uses a simple geometry. When you’re exporting Height Fields to a HDA, it has a lot of performance concerns due to the erosion nodes that need to cook and the File Caches I put down aren’t very useful when it comes to Height Fields. Unreal Engine doesn’t translate the $HIP expression and won’t be able to find the cache, thus it’ll think it’s empty and load nothing into the level of your game in Unreal Engine. The solution is simple, just put down a File Cache node that uses an absolute location path to the disk. For the last node before you finish off the HDA for the Height Field, put down an additional File Cache node that avoids using $HIP expression.

UE4’s Layer Blend Material Node

If you watched my video where I demonstrate how to use the data from Height Field volume primitives in UE when you export it as a HDA. You need to use the “Layer Blend” node in UE4’s material network editor and manually add the necessary slots and type in the names of the Height Field volume primitives to attach a color or texture to the landscape geometry.

To make it more convenient, I have included this snippet of code:

Begin Object Class=/Script/UnrealEd.MaterialGraphNode Name="MaterialGraphNode_0"
   Begin Object Class=/Script/Landscape.MaterialExpressionLandscapeLayerBlend Name="MaterialExpressionLandscapeLayerBlend_0"
   End Object
   Begin Object Name="MaterialExpressionLandscapeLayerBlend_0"
      Layers(0)=(LayerName="debris",LayerInput=(Expression=MaterialExpressionConstant3Vector'"MaterialExpressionConstant3Vector_0"'))
      Layers(1)=(LayerName="water",LayerInput=(Expression=MaterialExpressionConstant3Vector'"MaterialExpressionConstant3Vector_1"'))
      Layers(2)=(LayerName="sediment",LayerInput=(Expression=MaterialExpressionConstant3Vector'"MaterialExpressionConstant3Vector_4"'))
      Layers(3)=(LayerName="bedrock",LayerInput=(Expression=MaterialExpressionConstant3Vector'"MaterialExpressionConstant3Vector_3"'))
      ExpressionGUID=0AF6D57A47207EEFEDB9D8BC9C293A6F
      MaterialExpressionEditorX=224
      MaterialExpressionEditorY=128
      MaterialExpressionGuid=35C08D8641B24E0B93C91DA638FA2A66
      Material=PreviewMaterial'"/Engine/Transient.Landscape2_M"'
   End Object
   MaterialExpression=MaterialExpressionLandscapeLayerBlend'"MaterialExpressionLandscapeLayerBlend_0"'
   NodePosX=224
   NodePosY=128
   NodeGuid=245AC6514CAAAE77C354248611AC5926
   CustomProperties Pin (PinId=B459A262422A14FA2C14649F85999DC4,PinName="Layer debris",PinType.PinCategory="required",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(MaterialGraphNode_1 39AE3A604061DAEB748FA8B40FE95477,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=795DC4824AC7EC604CE0EFA1881830C7,PinName="Layer water",PinType.PinCategory="required",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(MaterialGraphNode_2 8FEC63024B9FF16F83878C8E14C7A710,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=5C0DBCD34FAF824AAA90DCA326F59970,PinName="Layer sediment",PinType.PinCategory="required",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(MaterialGraphNode_4 60765665490B9FEB54951187F5741766,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=B42F22DD4B111B727A7F259E9A38CF3C,PinName="Layer bedrock",PinType.PinCategory="required",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(MaterialGraphNode_3 91D713444966428244B5118AF0CE6DC4,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=834614714B4F60CB4F62E9A608F4DFED,PinName="Output",PinFriendlyName=" ",Direction="EGPD_Output",PinType.PinCategory="",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(MaterialGraphNode_Root_0 1B5F9883434CC283C1C9089D525CFD6F,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
UE4 Blend Layer Material Node already setup for Height Fields from Houdini

UE4 Blend Layer Material Node already setup for Height Fields from Houdini

Just copy the above snippet of code and go into the UE Material Editor and press CTRL + V to copy paste the code right into Unreal Engine. You will get the following attributes all setup for you, but this way it’s all automatically setup. The results are exactly the same like how I typed in each data primitive shown in the video, but this way you don’t have to type it in.

 
Houdini volume primitives.JPG

The debris, water, sediment, and bedrock are from the Houdini’s Height Fields, except I have excluded the mesa and cliffs. In the video I mention how the mesa and cliffs come from the terracing node and was creating these weird strip lines all over my Height Field terrain in UE4 after I applied my material.

 

Basic Landscape Material Setup

The bottom screenshots are demonstrating a super basic setup of a Landscape Material in UE4 without the use of mesa, cliffs, or bedrock data volume primitives given from Houdini’s erosion and terracing Height Field nodes.

TUT HF HDA to UE4.Frame with UE MAT without cliffs mesa.jpg
Very Basic Demo of Setting up Landscape Material in UE4 for a Houdini Height Field

Very Basic Demo of Setting up Landscape Material in UE4 for a Houdini Height Field