If you use ALandscape
in your scene, you may want to program the heights on it using code instead of manually brushing it in. To access the ALandscape
object and its functions inside of your code, you must compile and link in the Landscape
and LandscapeEditor
APIs.
Generating a landscape is not terribly challenging. You need to link in both the Landscape
and LandscapeEditor
APIs, and also have a programmatic way to set the height values across the map. In this recipe, we'll show how to use the Perlin noise for this.
Previously, you may have seen Perlin noise used for coloration, but that is not all it is good for. It is excellent for terrain heights as well. You can sum multiple Perlin noise values to get beautiful fractal noise. It is worth a brief study of Perlin noise to understand how to get good outputs.
noise1234.h
and noise1234.cpp
(or you can select another pair of noise generation files from this repository if you wish). Link these files into your project and be sure to #include YourPrecompiledHeader.h
into noise1234.cpp
.Landscape
and LandscapeEditor
APIs in your Project.Build.cs
file.Gen()
function. The Gen()
function can be attached to your Chapter12GameMode
derived class object as that is easy to retrieve from the engine. The Gen()
function must be BlueprintCallable UFUNCTION()
. (See the Creating a UFUNCTION section in Chapter 2, Creating Classes, for details on how to do so.)BeginPlay
event.ALandscape
object using code that does the following:Landscape
object in the level by searching through all objects in the Level
. We do this using a C++ function that returns TArray
of all Landscape
instances in the level:TArray<ALandscape*> AChapter12GameMode::GetLandscapes() { TArray<ALandscape*> landscapes; ULevel *level = GetLevel(); for( int i = 0; i < level->Actors.Num(); i++ ) if( ALandscape* land = Cast<ALandscape>(level->Actors[i]) ) landscapes.Push( land ); return landscapes; }
ULandscapeInfo
objects for ALandscape
editing using the very important line, which is as follows:ULandscapeInfo::RecreateLandscapeInfo( GetWorld(), 1 );
ALandscape
object so that we can compute the number of height values we will need to generate.LandscapeEditorUtils::SetHeightmapData( landscape, data );
to park new landscape height values into your ALandscape
object.For example, use the following code:
// a) REQUIRED STEP: Call static function // ULandscapeInfo::RecreateLandscapeInfo(). // What this does is populate the Landscape object with // data values so you don't get nulls for your // ULandscapeInfo objects on retrieval. ULandscapeInfo::RecreateLandscapeInfo( GetWorld(), 1 ); // b) Assuming landscape is your landscape object pointer, // get extents of landscape, to compute # height values FIntRect landscapeBounds = landscape->GetBoundingRect(); // c) Create height values. // LandscapeEditorUtils::SetHeightmapData() adds one to // each dimension because the boundary edges may be used. int32 numHeights = (rect.Width()+1)*(rect.Height()+1); TArray<uint16> Data; Data.Init( 0, numHeights ); for( int i = 0; i < Data.Num(); i++ ) { float nx = (i % cols) / cols; // normalized x value float ny = (i / cols) / rows; // normalized y value Data[i] = PerlinNoise2D( nx, ny, 16, 4, 4 ); } // d) Set values in with call: LandscapeEditorUtils::SetHeightmapData( landscape, Data );
The initial values of heightmap
will all be 32768
(SHRT_MAX
(or USHRT_MAX/2+1
)) when the map is completely flat. This is because the map uses unsigned shorts (uint16
) for its values, making it incapable of taking on negative values. For the map to dip below z=0
, the programmers made the default value half of the maximum value of heightmap
.
The Perlin noise function is used to generate a height value for (x, y) coordinate pairs. The 2D version of Perlin noise is used so that we can get a Perlin noise value based on 2-space spatial coordinates.
You can play with the Perlin noise functions with the spatial coordinates of the map, and assign the heights of the maps to different combinations of the Perlin noise function. You will want to use a sum of multiple octaves of the Perlin noise function to get more detail into the landscape.
The PerlinNoise2D
generation function looks as follows:
uint16 AChapter12GameMode::PerlinNoise2D( float x, float y, float amp, int32 octaves, int32 px, int32 py ) { float noise = 0.f; for( int octave = 1; octave < octaves; octave *= 2 ) { // Add in fractions of faster varying noise at lower // amplitudes for higher octaves. Assuming x is normalized, // WHEN octave==px you get full period. Higher frequencies // will go out and also meet period. noise += Noise1234::pnoise( x*px*octave, y*py*octave, px, py ) / octave; } return USHRT_MAX/2.f + amp*noise; }
The PerlinNoise2D
function accounts for the fact that the mid-level value of the function (sea level or flat land) should have a value of SHRT_MAX
(32768
).
3.140.191.34