Landscape creation using C++

New Text Document.txt (6.8 KB)

My code show I created 49 tiled landscapes in C++ with their assigned materials and it works fine!

The problem is that I assigned some layer info in code which is not replicating in the editor as shown in the screenshot. I have verified that the NewLayerInfo is valid but nothing seems to work.

Please if anyone know how to assign LandscapeLayerInfoObject to a landscape layer in C++ code, I would really appreciate the help :pray:.

1 Like

I fixed it and here is my updated code if any one is wondering:

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;
            landscapeLayersInfo.Add(FGuid(), MoveTemp(importLandInfo));

            proxy->Import(FGuid::NewGuid(), 0, 0, size_x - 1, size_y - 1, section_per_component, section_size, heightmapDataPerLayers, TEXT("MapHeightMap"), landscapeLayersInfo, ELandscapeImportAlphamapType::Additive);
            
            ULandscapeInfo* LandscapeInfo = proxy->GetLandscapeInfo();
            LandscapeInfo->UpdateLayerInfoMap(proxy);

            TArray<FLandscapeInfoLayerSettings>& ImportLandscapeLayersList = LandscapeInfo->Layers;
            for (int32 i = 0; i < ImportLandscapeLayersList.Num(); i++)
            {
                if (!ImportLandscapeLayersList[i].LayerInfoObj)
                {
                    FString LayerInfoPath = "/Game/Maps/LandscapeLayers/" + FString::FromInt(i + 1) + "_LayerInfo";
                    ULandscapeLayerInfoObject* NewLayerInfo = LoadObject<ULandscapeLayerInfoObject>(nullptr, *LayerInfoPath);
                    NewLayerInfo->LayerName = ImportLandscapeLayersList[i].LayerName;

                    if (NewLayerInfo)
                    {
                        ImportLandscapeLayersList[i].Owner = proxy;
                        ImportLandscapeLayersList[i].bValid = true;
                        ImportLandscapeLayersList[i].LayerInfoObj = NewLayerInfo;
                        ImportLandscapeLayersList[i].GetEditorSettings().LayerInfoObj = NewLayerInfo;
                    }

                    if (ImportLandscapeLayersList[i].LayerInfoObj)
                        ImportLandscapeLayersList[i].LayerInfoObj->MarkPackageDirty();
                }
            }

            Landscapes.Add(NewTile);
        }

        HeightmapIndex++;
    }
}

UE_LOG(LogTemp, Log, TEXT("Generated %d landscape tiles from heightmaps."), Landscapes.Num());

}

1 Like