Stick to the ground

Terrain correlation is always a pain. I’m receiving object locations from various external sources and there is an offset of a few metres. Each source has a slightly different height map meaning some objects appear as flying on top of the ground and others are under the ground.

Is there a way to force my objects to appear on the ground no matter the elevation?

Thanks,

I had a similar problem. I ended up using the LineTraceForObjects function.

You start with your object’s position, then you shoot a ray downward until you hit the ground, then you take that location and set it to your object’s location.

There’s an additional complication with this, because the earth tiles load in different LOD’s depending on how far away you are. This affects collisions also. This means that your object could be on the ground in one LOD, but not in the ground on another LOD. I’m not sure if there’s a way to handle this without checking every frame, but that’s what I had to do. I was able to get very reliable results using this. You just need to make sure you handle the case when the tile is completely removed because of camera culling.

The Cesium plugin has a bug right now, so the world’s collision is hard coding itself to WorldDynamic, so change that to WorldStatic when the plugin updates.

1 Like

Thanks for your reply. The same can be achieve from C++

TArray<TEnumAsByte<EObjectTypeQuery>> TraceObjects;
				TraceObjects.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));//add your object types here.
				TraceObjects.Add(UEngineTypes::ConvertToObjectType(ECC_WorldDynamic));//add your object types here.
				    FHitResult FirstHit(ForceInit);
    				TArray<AActor*> ActorsToIgnore;
    				ActorsToIgnore.Add(NULL);

    				if (UKismetSystemLibrary::LineTraceSingleForObjects(Engine->GetWorld(), startPos, FVector(0,0,-20000000), TraceObjects, false, ActorsToIgnore, EDrawDebugTrace::Persistent, FirstHit, false))
    				{
    					//collision detected
    				}

I tested it and it works well.

1 Like

Hey @jplebel, when I try to do SphereTraceSingleForObjects, I only get collision hits from static meshes I have placed into the level and none from Cesium landscape. However, if I run the blueprint equivalent function, it works on the Cesium landscape. I believe that the function is probably run before the landscape is loaded up on Play.

Had to add a timer in C++ to call the function after 3 seconds, thus the Cesium Landscape is loaded by them and it runs.
Code:
FTimerHandle handle;
float Delay = 3;
bool Loop = false;
GetWorldTimerManager().SetTimer(handle, this, &MyClass::MuFunction,Delay ,Loop);

I have struggled a lot with this issue. finally I found a solution.
first you should find distance between actor and earth surface by using “line trace by channel”(I created a function called “altimeter”)here is my function bluprint:


then you should subtract your current actor height (z) from output of altimeter, then set your actor location:

Thanks for sharing @epic_space!

I went ahead and made a new issue in the cesium-unreal repo to see if we can solve this with our plugin features. In theory, if all goes well, it’s as easy as a “Stick to ground” checkbox on one of our components.

1 Like

My approach involves using terrain TIF files and the Python GDAL library to implement an external API that retrieves elevation based on latitude and longitude. When placing an actor in UE, this API is used to query the elevation. While this method works, it is not as convenient as Cesium’s native solution. I hope Cesium can integrate this approach into their platform.