How does Unreal store height information of a Landscape?

I have difficulties in accessing the height information (per vertex) of a landscape in C++.

There is literally zero documentation for the Landscape classes (ALandscape, ULandscapeComponent etc.) within the engine code. Which makes things really really hard. I have following issues and questions:

  • How does unreal store height information? What is the main source of this data and where is it kept?

  • Is it kept inside HeightMapTexture variable of type UTexture2D within ULandscapeComponent? Is it always filled?

  • If HeightMapTexture is the main source this data, when is it filled? Can I access heightmap information from C++ code at editor time (not at run-time)?.

  • Why doesnt UTexture2D have some friendly interface methods to read/access pixels directly? (Just like Unity3d) why does it have to be this hard?

  • I’ve read in the below link that the pixel values of the UTexture2D is kept in the PlatformData variable. But accessing this data the way below gives me a nullpointer mip map data so it does not work.

link text

  • I’ve read somewhere else (dont remember the link) that the PlatformData variable is only initialized at run-time and is not set during editor time. There was another variable called Source within the UTexture2D which is supposed to keep this data at Editor time. I tried reading this with the following code:

      	FTextureSource & hmap_texture = (*i)->HeightmapTexture->Source;
      	check(hmap_texture.IsValid());
    
      	FColor * hmap_data = (FColor*)hmap_texture.LockMip(0);
      	for (int x = 0; x < hmap_size_x; x++) {
      		for (int y = 0; y < hmap_size_y; y++) {
      			FColor height = hmap_data[y*hmap_size_x + x];
                                  //TODO:Use height here...
      		}
      	}
      	hmap_texture.UnlockMip(0);
    

However this time all values written to height is gibberish. Visual Studio Debugger shows strange characters for the FColor channels instead of meaningful grayscale values.

  • What is the format of the height map. Unreal says it is TSF_BGRA8. But I suppose the height map is supposed to be grayscale image with a single 16 bit channel. How come the format becomes a 4 channel 32 bit image? Should I expect the height color (FColor in the code above) to have all channels equated to the same value (if I can successfully read it). Or am I suppose to convert the first two channels (or last two channels whatever) to 16 bit somehow to get the accurate data.

I would greatly appreaciate all help.

Basically all I want is as simple as getting the height (either as16 bit uint or something else) at each vertex of the landscape.

This problem (although it is very trivial) kept me occupied for more than a week now.

I had to dig deep into the UE code but I think I’ve found the answer.

The height map pixels use 32bit (4 channel) RGBA format. The first two channels represent the 16 bit height map. Therefore you need to bit shift the R channel by 8 bits and then use logical or operator to get the actual height. Se the code sample I’ve posted above and plug the below piece of code.

...........
uint16 height_value = (height.R << 8) | height.G;
...........

The B and A channels encode the tangents of the height map.

The first mip map (0) gives the full resolution height map. Other mip maps are divided by 2 in order. Also terrain mipmaps are generated differently than other texture mipmaps and they consider the 16 bit height values in the first two channels. Therefore it is safe to use the higher index mip maps (with lower resolution) if you desire.

Unreal height maps range from -256 to 256 meters within the scene. Therefore the height map having uint16:max would correspond to 256 meters. Of course you also need to take the Landscape actors scale into account. The z axis scale can effect this value in the game.

Another issue is that I think that the ULandscapeComponent’s HeightMapTexture members all correspond to the same height map that is the landscape height map. When I see this member within the ULandscapeComponent I thought that all components of the landscape do keep their own vertex height data within a separate texture. But this was wrong. So you need to sample the one and the unique Landscape actor heightmap for each vertex within a component if you want to export this height data somewhere.

2 Likes

Check Engine\Source\Runtime\Landscape\Public\LandscapeDataAccess.h and .cpp. There’s a bunch of related methods there to use or learn from. For precise results you need to be aware of that 2 bits seem to be reserved for other purposes (as LandscapeDataAccess::GetLocalHeight states). Therefore: float LocalHeight = LandscapeDataAccess::GetLocalHeight((Data->R << 8) + Data->G);

Hello Matiati. Did you work further on that issue? I am currently trying exactly the same.