In this post, we look at a very handy function available in UGameplayStatics and try to figure out why there is no convenient way to get UV of the collision with the Landscape in Unreal Engine.
From the official documentation, UGameplayStatics is:
Static class with useful gameplay utility functions that can be called from both Blueprint and C++
Essentially, it implements a bunch of functions which we routinely use withing Blueprints and C++, for example,
Let's start with looking at the function
FindCollisionUV from this neat little static class. This function accepts
FHitResult returned by a collision event, the UV channel and the UV itself and returns the UV coordinates for the collision impact location.
But it does so only if it is able to infer the coordinates - which is not always the case - Landscape being one of the actors for which this function fails.
Above is a screenshot from the Unreal Engine 5.1 codebase of the function. Disclaimer: The function is a copyright of Epic Games, Inc. and is used here for educational purposes only.
The very first
if clause checks if the feature flag is enabled from the project settings. The feature flag can be found under the "Physics Settings" section of the project settings menu in the editor and is called Support UV From Hit Results. The flag is disabled by default and enabling it leads to a small performance penalty.
If the flag is set, the function checks for the hit component and if the hit component overrides the
GetBodySetup() function. The
GetBodySetup() function is defined as a virtual function in the
UPrimitiveComponent and returns
NULL by default. The overriden implementions are expected to return the object,
UBodySetup, which contains the collision data at the asset level (rather than instances of the assets deployed in the level) for efficiency.
If the component does return a
UBodySetup, then the function proceeds to do the math in order to arrive at the UV coordinates at the local hit position computed from the collision location.
So why this does not work for Landscape?
Collisions with the Landscape return ULandscapeHeightfieldCollisionComponent which too is a sub-class of
UPrimitiveComponent but does not override the
GetBodySetup() function which is required by
Now why it does not override is not documented anywhere but our naive guess is that
UBodySetup works at an asset level (think an imported FBX or an OBJ) unlike Landscape where the geo is defined within the level with either brushes or heightmaps or a combination of both.
Again, this is our estimate. Someone at Epic Games, Inc. will definitely know better.