Hey man, I am also having the same issue but I can’t seem to understand the solution from your code!
Here is my code, everything works fine but the layers are not being set:
void ALandscapeManager::GenerateLandscapeTiles()
{
const int32 GridSize = 7;
const float Spacing = (TileSize - 1) * LandscapeScale.X;
int32 HeightmapIndex = 0;
for (int32 Row = 0; Row < GridSize; ++Row)
{
for (int32 Col = 0; Col < GridSize; ++Col)
{
FString HeightMapAddress = FString(HeightmapPath + "\\" + FString::FromInt(HeightmapIndex + 1) + ".png");
/*TArray<uint16> HeightData;
int32 Width, Height;
if (!LoadHeightmapFromPNG(HeightMapAddress, HeightData, Width, Height))
{
UE_LOG(LogTemp, Warning, TEXT("Failed to load heightmap: %d"), (Row * Col));
HeightmapIndex++;
continue;
}*/
FVector TilePosition = FVector(Row * Spacing, Col * Spacing, 0.0f) + FVector(0);
UWorld* world = GEditor->GetEditorWorldContext().World();
ALandscape* NewTile = world->SpawnActor<ALandscape>(TilePosition, FRotator(0));
ALandscapeProxy* proxy = Cast<ALandscapeProxy>(NewTile);
if (NewTile)
{
NewTile->bCanHaveLayersContent = true;
NewTile->SetActorScale3D(LandscapeScale);
int section_size = 63;
int section_per_component = 1;
int component_x = 4;
int component_y = 4;
int quads_per_component = section_per_component * section_size;
int size_x = 257;
int size_y = 257;
TArray<uint16> ImportLandscape_Data;
ILandscapeEditorModule& editorModule = FModuleManager::GetModuleChecked<ILandscapeEditorModule>("LandscapeEditor");
const ILandscapeHeightmapFileFormat* heightmapFormat = editorModule.GetHeightmapFormatByExtension(*FPaths::GetExtension(HeightMapAddress, true));
if (heightmapFormat)
{
FLandscapeHeightmapImportData HeightmapImportData = heightmapFormat->Import(*HeightMapAddress, { 257,257 });
if (HeightmapImportData.ResultCode == ELandscapeImportResult::Error)
{
UE_LOG(LogTemp, Error, TEXT("Failed to import heightmap: %s"), *HeightMapAddress);
return;
}
ImportLandscape_Data = MoveTemp(HeightmapImportData.Data);
}
TMap<FGuid, TArray<uint16>> heightmapDataPerLayers;
heightmapDataPerLayers.Add(FGuid(), ImportLandscape_Data);
UMaterialInstanceConstant* MaterialInstance = NewObject<UMaterialInstanceConstant>(NewTile->GetWorld(), UMaterialInstanceConstant::StaticClass());
if (!MaterialInstance)
{
UE_LOG(LogTemp, Warning, TEXT("Failed to create MaterialInstanceConstant."));
return;
}
MaterialInstance->SetParentEditorOnly(landscapeMaterial);
MaterialInstance->PostEditChange();
FString Layer1Path = "/Script/Engine.Texture2D'/Game/Maps/Textures/" + FString::FromInt(HeightmapIndex + 1) + "_1." + FString::FromInt(HeightmapIndex + 1) + "_1'";
FString Layer2Path = "/Script/Engine.Texture2D'/Game/Maps/Textures/" + FString::FromInt(HeightmapIndex + 1) + "_2." + FString::FromInt(HeightmapIndex + 1) + "_2'";
FString Layer3Path = "/Script/Engine.Texture2D'/Game/Maps/Textures/" + FString::FromInt(HeightmapIndex + 1) + "_3." + FString::FromInt(HeightmapIndex + 1) + "_3'";
UTexture2D* Layer1Tex = LoadObject<UTexture2D>(nullptr, *Layer1Path);
UTexture2D* Layer2Tex = LoadObject<UTexture2D>(nullptr, *Layer2Path);
UTexture2D* Layer3Tex = LoadObject<UTexture2D>(nullptr, *Layer3Path);
if (MaterialInstance)
{
if (Layer1Tex) MaterialInstance->SetTextureParameterValueEditorOnly(FName("Grass Layer"), Layer1Tex);
if (Layer2Tex) MaterialInstance->SetTextureParameterValueEditorOnly(FName("Rock Layer"), Layer2Tex);
if (Layer3Tex) MaterialInstance->SetTextureParameterValueEditorOnly(FName("Sand Layer"), Layer3Tex);
// Apply the material instance back to the landscape
for (ULandscapeComponent* Component : NewTile->LandscapeComponents)
{
Component->MarkRenderStateDirty();
}
NewTile->LandscapeMaterial = MaterialInstance;
}
TArray<FLandscapeImportLayerInfo> importLandInfo;
TMap<FGuid, TArray<FLandscapeImportLayerInfo>> landscapeLayersInfo;
if (landscapeMaterial != nullptr)
{
TArray<FName> layerNames = ALandscapeProxy::GetLayersFromMaterial(landscapeMaterial);
importLandInfo.Reserve(layerNames.Num());
for (int32 i = 0; i < layerNames.Num(); ++i)
{
FString LayerInfoPath = "/Game/Maps/LandscapeLayers/" + FString::FromInt(i + 1) + "_LayerInfo";
ULandscapeLayerInfoObject* NewLayerInfo = LoadObject<ULandscapeLayerInfoObject>(nullptr, *LayerInfoPath);
if (NewLayerInfo)
{
FLandscapeImportLayerInfo ILayerInfo;
ILayerInfo.LayerName = layerNames[i];
ILayerInfo.LayerInfo = NewLayerInfo;
importLandInfo.Add(MoveTemp(ILayerInfo));
}
}
}
landscapeLayersInfo.Add(FGuid(), MoveTemp(importLandInfo));
for (const auto& layer : landscapeLayersInfo)
{
UE_LOG(LogTemp, Warning, TEXT("Guild: %s"), *layer.Key.ToString());
for (const auto& layerInfo : layer.Value)
{
UE_LOG(LogTemp, Warning, TEXT("Layer info : %s"), *layerInfo.LayerName.ToString());
UE_LOG(LogTemp, Warning, TEXT("Layer info : %s"), *layerInfo.LayerInfo.GetFName().ToString());
}
}
proxy->Import(FGuid::NewGuid(), 0, 0, size_x - 1, size_y - 1, section_per_component, section_size, heightmapDataPerLayers, TEXT("MapHeightMap"), landscapeLayersInfo, ELandscapeImportAlphamapType::Additive);
Landscapes.Add(NewTile);
}
HeightmapIndex++;
}
}
UE_LOG(LogTemp, Log, TEXT("Generated %d landscape tiles from heightmaps."), Landscapes.Num());
}