Search code examples
c++unreal-engine4

Landscape Creation C++ UE4.27


I would like to create a landscape from scratch in unreal engine 4.27 using C++ only. I have only a simple notion of the process, which revolves around GetWorld()->SpawnActor<ALandscape>, ALandscapeProxy::Import(...) and importing a height/weight map.


I used the LandscapeEditorDetailCustomization_NewLandscape::OnCreateButtonClicked() method as a learning ground, but unfortunately I am at an impasse.


From what I have gathered from my searches there not a lot of examples on the matter. Does anyone have a suggestion or an example?


Solution

  • This is the solution I came up with, with many thanks to ChenHP (or chpsemail) who gave me a solution to this. Firstly, declare the following variables. A better understanding can be found here.

    FQuat InRotation
    FVector InTranslation
    FVector InScale
    FTransform LandscapeTransform{InRotation, InTranslation, InScale}
    int32 QuadsPerSection
    int32 SectionsPerComponent
    int32 ComponentCountX
    int32 ComponentCountY
    int32 QuadsPerComponent
    int32 SizeX
    int32 SizeY
    

    Create containers for the heights and materials of the landscape:

    TArray<FLandscapeImportLayerInfo> MaterialImportLayers
    TMap<FGuid, TArray<uint16>> HeightDataPerLayers
    TMap<FGuid, TArray<FLandscapeImportLayerInfo>> MaterialLayerDataPerLayers
    

    It is important to note that heights in UE4 are of uint16 type, with 0 the deepest and 65'534 the highest. So for a flat map all height entries should be 32768. The number of heights is the resolution of the map which is dependent on SizeX and SizeY.

    TArray<uint16> HeightData;
    HeightData.SetNum(SizeX * SizeY);
    for (int32 i = 0; i < HeightData.Num(); i++)
    {
        HeightData[i] = 32768;
    }
    

    Height and material information should then be placed in the corresponding containers and be given a valid FGuid.

    HeightDataPerLayers.Add(FGuid(), MoveTemp(HeightData))
    MaterialLayerDataPerLayers.Add(FGuid(), MoveTemp(MaterialImportLayers))
    

    At this point the base parameters for the landscape have been set. The ALandscape* Landscape = SpawnActor<ALandscape>() could be called at either point since it just spawns an object that doesn't actually have any information about it. This also applies for setting landscape's fields. Fields that need to be set are presented bellow:

    Landscape->bCanHaveLayersContent
    Landscape->LandscapeMaterial
    Landscape->SetActorTransform
    Landscape->StaticLightingLOD
    ULandscapeInfo* LandscapeInfo = Landscape->GetLandscapeInfo()
    LandscapeInfo->UpdateLayerInfoMap(Landscape)
    Landscape->RegisterAllComponents()
    Landscape->GetClass()
    Landscape->PostEditChangeProperty(MaterialPropertyChangedEvent)
    Landscape->PostEditChange()
    

    The actual part where landscape is given form, happens with the invocation of Landscape->Import(...).


    A detailed explanation about what the script could look like can be found here with more information on landscape (check the answer for the cpp code).