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?
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).