I have a landscape in editor that we have setup a number of LandscapeLayerInfoObjects on for painting down information that is used for editor time PCG, I also have the more standard use of LandscapeLayerInfoObjects for creating blend maps for our RVT landscape textures.
When cooking the build I have noticed that the weightmap cost of the terrain is very high and is showing the same number of weightmaps as the “Landscape Usage” view. For example: if I had a landscape with a usage of 11, I am seeing 3 weightmaps being cooked. I understand this is the correct number as it will use as many 4 channel textures it needs to contain 11 layers and in this case I have 1 channel that is unused in 1 texture. This is all correct if they were used in the RVT material, however, only 2 of these layers are runtime layers referenced in my RVT material. The other layers are not referenced or needed for runtime so I would expect just the 2 layers to be packed in to 1 weightmap texture with 2 channels not used.
Is there a way I can tell the cook to ignore these other layers when making the weight maps? It would substantially reduce my weightmap cost across the map.
Hi,
Unfortunately, no, there is no way currently to have some landscape target layers be “editor-only”. The weightmaps are identical in-editor and at runtime and the material instance constant that gets built per-component is also identical because it depends on these weightmaps (it’s a static variation of the landscape material that binds the particular weightmaps used on a given component).
Some time ago, there was a plan to implement that specific feature, which is why it’s now possible to declare target layers in the landscape editor, even if the landscape material doesn’t use these layers (while in the past, the layers had to be declared in the landscape material before being usable in the landscape, in other words, the landscape material was the place that was “driving” the target layers). This was a substantial effort in itself that we managed to finish in UE5.6, I believe. Unfortunately, the second part of the plan was to separate the editor data (weightmaps / materials) from the runtime data, so that we could mark certain target layers as editor-only, as well as to let the user visualize and paint those layers (since they’re not part of the material, they would not be renderable unless we implemented the tooling for this). That was also a substantial effort to implement and one that we have yet to find the time for.
With the UE6.0 announcement, you may have noticed the announcement of Mesh Terrain, our new solution for landscape-style workflows. As you might guess, realistically, this will mean that no major new landscape feature such as what we discussed here will be implemented.
I hope this clarifies things a bit.
Cheers,
Hi Jonathan,
That’s a shame. We will probably write a cook-time striping function to remove the unwanted layers.
Thanks for the quick and detailed response.
Hey [mention removed] , thanks from me for your earlier response.
We’ve been thinking on this and are considering the following approach: a runtime cell transformer that sets the opacity of the unwanted layers to zero. We then expect that will remove those layers during cook.
Do you expect that will work? Does it seem like the right approach with the tools at hand?
Thanks in advance,
Mike
Hi again, sorry for the late answer, the company was in summer break.
If your world is a world partition-only, then I suppose that could be an approach you could take to avoid changing the landscape (engine) code. What you’ll need to do is remove the layer allocations entirely from the landscape components. Have a look at what is done in ALandscape::UpdateForChangedWeightmaps : you’ll need to 1. remove the layer allocations 2. update the material instances on the affected components.
// If this component has a layer with only zeros, remove it so that we don't end up with weightmaps we don't end up using :
if (!ComponentReadbackResult.AllZeroLayers.IsEmpty())
{
const TArray<FWeightmapLayerAllocationInfo>& ComponentWeightmapLayerAllocations = ComponentReadbackResult.LandscapeComponent->GetWeightmapLayerAllocations(FGuid());
for (ULandscapeLayerInfoObject* AllZeroLayerInfo : ComponentReadbackResult.AllZeroLayers)
{
check(AllZeroLayerInfo != nullptr);
// Find the index for this layer in this component.
int32 AllZeroLayerIndex = ComponentWeightmapLayerAllocations.IndexOfByPredicate(
[AllZeroLayerInfo](const FWeightmapLayerAllocationInfo& Allocation) { return Allocation.LayerInfo == AllZeroLayerInfo; });
check(AllZeroLayerIndex != INDEX_NONE);
ComponentReadbackResult.LandscapeComponent->DeleteLayerAllocation(FGuid(), AllZeroLayerIndex, /*bShouldDirtyPackage = */true);
// We removed a weightmap allocation so the material instance for this landscape component needs updating :
ComponentsNeedingMaterialInstanceUpdates.Add(ComponentReadbackResult.LandscapeComponent);
}
}
[...]
UpdateLayersMaterialInstances(ComponentsNeedingMaterialInstanceUpdates);
Essentially, that’s what removing a landscape layer involves. Make sure that those layers don’t participate to anything else in the material like landscape grass output or landscape physical output, because then, the (offline-computed) grass density data and the dominant physical material data will both be incorrect.
Of course, this is not the direction we would take for landscape in the engine as a whole, because it would only work for world partition, but the runtime cell transformer approach doesn’t seem like a bad idea if you’re positive you won’t ever be in that situation.
Cheers,
Thanks for your answer, we’ll give that a try… Much appreciated!