Questions about World Partitioned Actor Cell Level and Manually Assign HLOD Meshes

These appear to be two unrelated issues, but in reality, we encountered the second problem while avoiding the first. For the sake of explanation, I have raised both issues in the same post.

Q1: About the cell level (grid level) of large actors

I understand that if a mesh’s bounds exceed the size of a cell, it will be moved to a higher-level cell. Based on my observations, it appears the highest level is 5/6. If a mesh is so large that even the highest-level cell cannot contain it, will this mesh not be spatially load / unload ? Is this behavior consistent in 5.5/5.6?

  • We are facing a problem that a very large mesh may be loaded and unloaded incorrectly. Through debugging, we discovered that this mesh resides in the top-level cell, yet the size of this cell does not match the size of the mesh.
  • We dumped the bounding box of the actor and the cell:
Actor : Min=(X=295092.230 Y=1378677.800 Z=-4621.811)、Max=(X=525987.394 Y=1614103.779 Z=1052.227)
Cell : Min=(X=409600.000 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=0.000)
  • It appears that this Cell was truncated at position 409600.As background information: our Cell Size is set to 102400. It seems 409600 is exactly four times that value.

As additional info:

Actor
 |   |   |- [+] [2312]
 |   |   |   |- Guid:4D7E3C104F32ACF8674B31833D3E1BD4 NativeClass:/Script/XXX.XXXX Name:XXXXX_UAID_3C7C3F50F21C147C02_1633955372 Label:SM_XXXXX SpatiallyLoaded:true EditorBounds:IsValid=true, Min=(X=295092.230 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=1052.227) RuntimeBounds:IsValid=true, Min=(X=295092.230 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=1052.227) RuntimeGrid:None EditorOnly:false RuntimeOnly:false HLODRelevant:true ListedInSceneOutliner:true IsMainWorldOnly:false HLODLayer:/Game/<XXXX>/MainGridISMOnly_HLOD.MainGridISMOnly_HLOD FolderPath:XXXX FolderGuid:45D1E97A42DE88B1B1F590B5FEC84D85
 
Cell
[+] Content of Cell Level_XXX_MainGrid_L5_X1_Y3_Z-1 (67C0KXQOI1CTROTZ5PN0Z88WI)
 |- Actor Count: 1
 |- Content Bounds: IsValid=true, Min=(X=409600.000 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=0.000)
 |- Cell Bounds: IsValid=true, Min=(X=409600.000 Y=1228800.000 Z=-409600.000), Max=(X=819200.000 Y=1638400.000 Z=0.000)
 |- Is 2D: False
 |- [+] /Game/<XXXX>/Level_XXX.Level_XXX:PersistentLevel.XXXXX_UAID_3C7C3F50F21C147C02_1633955372
 |   |-         Package: /Game/__ExternalActors__/<XXXX>/9/YJ/YOGIOAIXEK4FFYQFI0624G
 |   |-     Editor Only: 0
 |   |-   Instance Guid: 4D7E3C104F32ACF8674B31833D3E1BD4
 |   |- [+] Container:
 |   |   |-        ID: 00000000000000000000000000000000
 |   |   |- Transform: 0.000000,0.000000,0.000000|0.000000,0.000000,-0.000000|1.000000,1.000000,1.000000

​To temporarily sidestep this issue, our artists decided to slice the massive mesh into smaller pieces.

Q2: Can I assign a proxy HLOD mesh for a set of actors sliced from a huge mesh?

Can I manually specify a series of Mesh Actors that should be forced to merge into a single HLOD Mesh, and manually designate this HLOD Mesh?

  • Practical use case: Our artists have sliced a mountain into multiple smaller chunks. We want all these chunks to be replaced with a pre-made low-poly mountain mesh when viewed in the distance, rather than having the engine generate an Approximated Mesh for us.​

Hello!

Q1: Can you share details regarding the World Partitions settings you are using? A screenshot from the World Settings panel would help. We’ve seen this kind of behavior in the past when RuntimeSpatialHash was the default grid type for World Partition, but I would expect RuntimeHashSet to behave differently. If you are still using RuntimeSpatialHash, make sure you use the following cvar settings:

wp.Runtime.RuntimeSpatialHashUseAlignedGridLevels=0
wp.Runtime.RuntimeSpatialHashSnapNonAlignedGridLevelsToLowerLevels=0
wp.Runtime.RuntimeSpatialHashPlaceSmallActorsUsingLocation=1
wp.Runtime.RuntimeSpatialHashPlacePartitionActorsUsingLocation=0

Q2: At the moment, you can’t provide a custom HLOD mesh for a group of actors. This is a feature currently being worked on and it should hopefully be available in 5.7. However, you could achieve mostly the same result by slicing that custom HLOD mesh, and assigning it as the last LOD of each mountain part. Then, using a Merged Mesh HLOD layer, you would get a single HLOD mesh which would be the sum of all those last lLODs, untouched. Just make sure not to bake down materials.

Regards,

Sebastien

Hello!

Actually that might have been misleading because, at runtime, what is going to be used for distance streaming is the cells “Content Bounds” value, which in your case fully encompass the actor:

Content Bounds: IsValid=true, Min=(X=409600.000 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=0.000)

| We are facing a problem that a very large mesh may be loaded and unloaded incorrectly.

Are you saying the content bounds isn’t used in your case ?

Sorry, I now understand where the difference is coming from between your results and mine…

You are missing a change that didn’t make it in 5.5

Content Bounds of higher level cells (> L0) should be left untouched

You can apply the following fix:

https://github.com/EpicGames/UnrealEngine/commit/6fcf7beaec98db5dad78048e8cf5298f8dffa346

Let me know if this works for you!

Regards,

Sebastien

Hi Sebastien! Really thanks for following this problem.

For Q2, thanks for your answer. I think I got the info I want. Let’s focus on Q1.

> Can you share details regarding the World Partitions settings you are using? A screenshot from the World Settings panel would help.

This is our settings:

[Image Removed]

> If you are still using RuntimeSpatialHash

No we are using WorldPartitionRuntimeHashSet

> make sure you use the following cvar settings

I found these settings in our DefaultEngine.ini

wp.Runtime.RuntimeSpatialHashUseAlignedGridLevels=0
wp.Runtime.RuntimeSpatialHashSnapNonAlignedGridLevelsToLowerLevels=0
wp.Runtime.RuntimeSpatialHashPlaceSmallActorsUsingLocation=1
wp.Runtime.RuntimeSpatialHashPlacePartitionActorsUsingLocation=1

Since we are using RuntimeHashSet, I don’t think this is related to our problem, right?

Thanks!

Luo

Hi Sebastien!

> which in your case fully encompass the actor:

I really don’t think it is. Or did I misunderstand something?

> Content Bounds: IsValid=true, Min=(X=409600.000 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=0.000)

> Actor Runtime Bounds: Min=(X=295092.230 Y=1378677.800 Z=-4621.811), Max=(X=525987.394 Y=1614103.779 Z=1052.227)

If I visualize the actor bounds in red, and the content bounds in green. I think the content bound doesn’t encompass the actor?

[Image Removed]

Hi Sebastien!

Really thanks for your info, a quick test shows it fixed the problem!