Procedural Landscapes - editing the heightmap in C++?

Hi there,

I’m loving the new Landscape system. I’ve combed over the documentation but I’m not certain if there’s a way to achieve what I want - at runtime, would I be able to change the heightmap of a terrain? For example, I plan to use LibNoise as a plugin to generate my landscapes on the fly. Is this possible?

Thanks!

It’s possible with some dances around, but you have to check the Landscapes code. It’s not a “documented” thing.

Any pointers? I’ve had a browse but it seems quite non-obvious.

I’m trying to do add a kind of geommip mapping and I need to modify the heightmap too.

Here is the code I’m working on.




//my input is a landscape object
void UUpdateLandscape::UpdateTile(ALandscape *landscape)
{

UTexture2D *heightMap = landscape->LandscapeComponents[0]->HeightmapTexture;
EPixelFormat formatPixel = heightMap->GetPixelFormat();

//texture resolution
int sizeX = heightMap->GetSizeX();
int sizeY = heightMap->GetSizeY();

int pixelSize = sizeof(formatPixel)*8;
int pitch = pixelSize * sizeX;

FUpdateTextureRegion2D region;
region.DestX = 0;
region.DestY = 0;
region.SrcX = 0;
region.SrcY = 0;
region.Width = sizeX;
region.Height = sizeY;



                                //foreach pixel, I will change the height. Today, it's done by the CPU but I will move it later to the GPU
				for (int x = 0; x < sizeX; x++)
				{
					for (int y = 0; y < sizeY; y++)
					{
						
					}
				}

heightMap->UpdateTextureRegions(0, 1, &region, pitch, pixelSize, NULL, false);
}



Today, the new data pointer is set to NULL but I’ve a problem when I compile the file. The linking operation failed because visual studio doesn’t find "external reference. I’m searching why and I let you know later if this code is working (or not…).

Any update on this? I’ve ran into the same problem, and I’d love to know a solution

Nevermind, I figured this out

Would love it if you shared your solution.

What did you found.

wisdom_of_the_ancients.png

WHAT DID YOU SEE, MatrixCompSci!!!

1 Like

I’m inputing wild numbers from 0 to 255 into that piece of code set there but nothing gets shown in the landscape when the level starts… Is there any missing call to make the landscape dynamically update after the texture changes?

https://docs.unrealengine.com/en-US/…ers/index.html

https://docs.unrealengine.com/en-US/…int/index.html

https://dq8iqaixvew1d.cloudfront.net…ent/index.html

The code for the layer brushes lives in the “Runtime” part of Landmass, so I think you should just be able to turn this on, create displacements, and go wild!
Don’t use static/pre-computed lighting, though …

If that doesn’t work, you can use world offset in landscape materials, if you enable that checkbox on the landscape actor. Turn on world offset, sample a dynamic texture, material moves!

I recently managed to write custom heightmap data to the Landscape using the helper class FHeightmapAccessor. I haven’t tried it in runtime yet though, but I think it might be possible.

  1. As a starting point, have a look at the following function, found in /Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdMode.cpp
bool LandscapeEditorUtils::SetHeightmapData(ALandscapeProxy* Landscape, const TArray<uint16>& Data)
{
	FIntRect ComponentsRect = Landscape->GetBoundingRect() + Landscape->LandscapeSectionOffset;

	if (Data.Num() == (1 + ComponentsRect.Width())*(1 + ComponentsRect.Height()))
	{
		FHeightmapAccessor<false> HeightmapAccessor(Landscape->GetLandscapeInfo());
		HeightmapAccessor.SetData(ComponentsRect.Min.X, ComponentsRect.Min.Y, ComponentsRect.Max.X, ComponentsRect.Max.Y, Data.GetData());
		return true;
	}

	return false;
}

…and just replicate that code. You don’t want to use that function directly since it is in an Editor module. The FHeightmapAccessor will update the internal textures, includig mips, and recalculate the normals for you.

ComponentsRect corresponds to the number of quads, meaning that for example Width() + 1 is the number of vertices along the X-axis.

If you want to manually set normals etc, just look inside the implementation of SetData() and replicate what it does but pass also normal data etc to LandscapeEdit->SetHeightData(...).

  1. Though, you probably first need to convert your floating point heights to uint16 packed for the heightmaps. You can do it like this, per height in your array:
#include "LandscapeDataAccess.h"

...

float HeightCm = /* height in centimeter */
float HeightLocal = HeightCm / Landscape->GetTransform().GetScale3D().Z;
uint16 HeightTex = LandscapeDataAccess::GetTexHeight(HeightLocal);
1 Like