Landscape HLODs are broken in 5.7.2 (Github Release branch)

Landscape HLODs are broke when build from Editor. See repro steps above. I have not provided a repro project as it uses the open world starter map.

[Attachment Removed]

Steps to Reproduce
Landscape HLODs are broken when built from editor, either by clicking build on a specific landscape HLOD actor tile or by running the commandlet for the level via the build drop down menus.

I tested two setups, both based on the open world starter map. In test case A I modified the level such that the landscape material used RVTs. In test case B I simply modified the RGB material, no RVTs. In both test cases the landscape was nanite enabled.

Test Case A:

HLODs superimposed on Landscape

[Image Removed]

Just HLODs:

[Image Removed]

The landscape material simply writes out the green color to a RVT and then resamples said RVT to output base color. The landscape HLODs are completely black. I suspect this has something to do with the fact that the new BuildHLODWorld is not correctly setup.

When rebuilding a specific tile via the build button, the result is as follows:

[Image Removed]

I have determined that the grey color we are seeing is the world grid material being used to render the landscape tile during the rendertotexture(…) call as part of the Bake Landscape Material process. The reason for the world grid material is simply due to the fact that the shader map for the actual material used on the landscape is not ready and so it falls back to the world grid material. Later in this post is a render doc capture showing the landscape being rendered with a world grid material.

Test Case B:

Below is a screen shot of the landscape HLOD superimposed over the landscape.

[Image Removed]

Here is the same, but with the landscape hidden

[Image Removed]

In test case B, when building via the commandlet, things work correctly. However, building via the landscape HLOD tile by clicking the “build HLOD” button leads to incorrect results.

On the first attempt to build HLODs via the tools drop down on the HLOD actor (“Build HLOD” button) we get a correct result. On any subsequent attempt, on any other HLOD actor results in a grey HLOD tile. Here is what it looks like, after attempt > 1 (I have numbered my attempts in blue):

[Image Removed]

Here we can see the same behaviour exhibited as in Test Case A. When building a specific tile via the HLOD actor the tile is captured with the world grid material rather than the landscapes actual material. As mentioned before, this is because it can no longer find the shader to render the material in the Build HLOD temporary world. It is curious that it works on the first attempt, this is not the case when working with RVTs.

I made a Render Doc capture, with nanite disabled on the landscape for easier debugging. The bug persists and behaves the same regardless of nanite.

Render Doc Capture events 1883 and 4051 show the basepass and post process material draw calls.

BasePassParallel:

[Image Removed]

Post Process Material (Base Color):

[Image Removed]

[Attachment Removed]

Hi Tom. Thanks for the detailed report. I can confirm that I see the same wrong behavior. We’ll investigate.

[Attachment Removed]

Hi Tom. Unfortunately, no updates at this time.

[Attachment Removed]

Hi, just as a quick update here, it was determined that this wasn’t a problem with the landscape code, so this is being moved to the world building team to investigate further.

[Attachment Removed]

Hi Tom!

There were actually multiple issues compounded here. You should be able to resolve them by grabbing the following changes:

https://github.com/EpicGames/UnrealEngine/commit/2a4ac5784771637bf6493514a3f84b50c4b6b437

https://github.com/EpicGames/UnrealEngine/commit/534017e5432da154322ac67507128622ec73599d

https://github.com/EpicGames/UnrealEngine/commit/d28e49d98d1025ad318406a7de6cc7b9c666b88e

Let me know if this works for you!

Regards,

Sebastien

[Attachment Removed]

Hi Sebastien,

Sorry for the late reply. Thank you very much for sharing the changes. We’ve found the change to force compile all required shaders helped, but the others did not in our project. We’ve made some additional changes that helped us; I’m getting the team to compile the information so I can share the details.

[Attachment Removed]

Hi Sebastien,

We have observed the same issue, and it indeed caused by RVT not being rendered (UE 5.7).

Currently, when Building HLODs:

  1. Source World registers it’s RVT Actors and Components.
  2. When building HLODs a new temp working UWorld (named BuildHLODWorld) is created.
  3. HLODs being built load up their source Landscape Actors.
  4. The Landscape actors are then ‘cloned’ from the original source world into BuildHLODWorld.
  5. ExportLandscapeMaterial is eventually called to Render BuildHLODWorld’s Scene (FSceneInterface).

Notice that BuildHLODWorld is rendered but never had the Source World’s RVT Actors and Components ‘cloned’ into it.

Since there are no RVT Actors and components in BuildHLODWorld, the RVT is never rendered.

We are currently testing a solution which appears to work.

  1. Implement IsHLODRelevant for ARuntimeVirtualTextureVolume and URuntimeVirtualTextureComponent. Should return true in both cases.
  2. Modified UWorldPartitionHLODSourceActorsFromCell::LoadSourceActors to collect ARuntimeVirtualTextureVolume Actors from the source world.

Here’s a code snippet (below).

If you have any suggestions and comments regarding these observations and our tentative fix (WIP), would be much appreciated.

Best,

David

bool UWorldPartitionHLODSourceActorsFromCell::LoadSourceActors(bool& bOutDirty, UWorld* TargetWorld) const
...
TArray<FWorldPartitionRuntimeCellObjectMapping> ActorsCopy = Actors;
 
// WIP: 
// Collect ARuntimeVirtualTextureVolume actors and add them to 'ActorsCopy '
//
for (TActorIterator<ARuntimeVirtualTextureVolume> It(SourceWorld); It; ++It)
{
	FWorldPartitionActorDescInstance* Desc = It->GetWorld()->PersistentLevel->GetWorldPartition()->GetActorDescInstance(It->GetActorGuid());
	UActorDescContainerInstance* DescContainer = Desc->GetContainerInstance();
 
	FWorldPartitionRuntimeCellObjectMapping& RVTItem = ActorsCopy.AddDefaulted_GetRef();
	RVTItem.Path = FName(It->GetPathName());
	RVTItem.Package = It->GetPackage()->GetFName();
	RVTItem.BaseClass = FTopLevelAssetPath(*It);
	RVTItem.NativeClass = FTopLevelAssetPath(*It);
	RVTItem.ContainerID = DescContainer->GetContainerID();
	RVTItem.ContainerTransform = DescContainer->GetTransform();
	RVTItem.EditorOnlyParentTransform = DescContainer->GetTransform();;
	RVTItem.ContainerPackage = DescContainer->GetPackage()->GetFName();
	RVTItem.WorldPackage = It->GetWorld()->GetPackage()->GetFName();
	RVTItem.ActorInstanceGuid = Desc->GetGuid();
	RVTItem.LoadedPath = It->GetPackage()->GetLoadedPath().GetPackageFName();
}
...

[Attachment Removed]

Hi David,

Great analysis - your diagnosis of the root cause is spot on. The RVT actors and components not being cloned into BuildHLODWorld is indeed the problem.

Regarding your two-part fix:

The LoadSourceActors modification to collect ARuntimeVirtualTextureVolume actors from the source world is the right approach. The RVT volumes need to be present in the build world so that landscape materials that sample from the RVT render correctly during HLOD capture.

However, I don’t think implementing IsHLODRelevant for ARuntimeVirtualTextureVolume and URuntimeVirtualTextureComponent is necessary (or desirable). IsHLODRelevant controls whether an actor type is treated as a source contributor to HLODs — meaning it has visual geometry that should be merged into the HLOD representation. RVT volumes don’t have geometry to contribute; they’re rendering infrastructure. Marking them as HLOD-relevant could cause the builder to needlessly process them as geometry sources and would result in them being redundantly included in every cell’s actor list. Your LoadSourceActors change alone should be sufficient since it gets the RVT volumes into the build world as dependencies for correct rendering, without them being treated as HLOD geometry contributors.

Let me know how testing goes with just the LoadSourceActors change.

Regards,

Sebastien

[Attachment Removed]

Hi Sebastien,

Now that the HLOD texture is generated, we have noticed some black borders around the edges of the HLOD texture?

The result is that when all HLODs texture are generated, it looks like there are black seams and visually looks like a grid is overlayed on top of the landscape.

Is that something your team has also been tracking?

Should I create a new ticket for that?

Thanks,

David

[Attachment Removed]

Hi all,

We have found similar. It has been reported in the community forums:

And UEFN:

Cheers,

Tom

[Attachment Removed]

That grid like pattern has been fixed with the following change:

https://github.com/EpicGames/UnrealEngine/commit/2a4ac5784771637bf6493514a3f84b50c4b6b437

[Attachment Removed]

“We are seeing good results, but are concerned that this might force Fallback mesh to be used when generating the HLOD geometry? What impact wil this have?”

[Content removed] which is really desireable if you are using Nanite for the rest of your project.

Ultimately if you are using Nanite and SRVT I think the best solution is to use the example setup in the post provided by Yanchen Li

It avoids the need to perform any kind of texture baking for landscape HLODs, which is really a waste of resources given the fact that the SRVT exists with similar (and probably higher quality) data.

This is the setup that was used in the Witcher 4 demo, so it’s been battled tested :slight_smile:

Regards,

Sebastien

[Attachment Removed]

Hi Alan. Thank you for confirming the repro. Any update on your investigation?

[Attachment Removed]

In Case A, the FRuntimeVirtualTextureFinalizer instance may reside in a different UWorld within the commandlet context, resulting in a mismatched GPUScene.

[Attachment Removed]

Hello, any update from the world building team? Any ETA on when it might get looked at/resolved? Cheers!

[Attachment Removed]

Hi Sebastien,

Appreciate the feedback, I seem to recall the RVT component got filtered out in my early tests.

I will revalidate regarding HLOD relevance.

Otherwise HLODs do generate correctly with the proposed code fix.

Would be very appreciated to get an update if there is a CL to fix this in the vanilla codebase.

Best,

David

[Attachment Removed]

Hi Sebastien,

Unfortunately after integrating the suggested CL, we are still getting black jagged edges around the generated HLOD textures.

Please let us know if there are any further updates regarding a fix.

Thanks,

David

[Attachment Removed]

We’ve found that disabling Nanite during landscape material baking as a workaround successfully eliminates the black jagged edges.

[Attachment Removed]

Hi David,

We have applied this exact change and fixed our issues too.

[Attachment Removed]