Flying Between Locations - jgoffeney/Cesium4Unreal GitHub Wiki

Back

Description

This page describes the basics for moving the DynamicPawn between locations on the globe. On initialization I read the geospatial bounds for each tile set to use as the fly-to point. When pressing return the pawn flies to the next location.

Reading the Target Points

The geospatial target coordinates are read from the JSON source files and are stored in an array.

Moving to Location

Setting Up Inputs

Go to Edit->Settings->Engine->Input and add a new ActionMapping. I set up one for the Enter key and named it NextSource.

EngineInputs

To listen for the keypress the Actor method SetupMyPlayerInputComponent is implemented and within the body the keypress action is mapped to the listener function.

// Called to bind functionality to input
void SetupMyPlayerInputComponent(UInputComponent* myInputComponent);
void ACesium3dTileApplication::SetupMyPlayerInputComponent(UInputComponent* myInputComponent) {
    myInputComponent->BindAction("NextSource", IE_Pressed, this, &ACesium3dTileApplication::MoveToNextSource);
}

Initial Location

Within BeginPlay() I set the initial location from my first tile set with the top center point of the geospatial bounding volume with 500 meters added to the height. The geospatial coordinates are converted to Unreal coordinates using the CesiumGeoreference object which can then be passed into th SetActorLocationAndRotation method for the DynamicPawn object. Note: I have not gotten the initial pawn rotation to work correctly.

_currentSourceIndex = 0;
glm::dvec3 sourceGeoLocation = _sources->GetSourceInfo(0)->GetUpperCenterGeoPoint();
currentGeoLocation = FVector(sourceGeoLocation.x, sourceGeoLocation.y, sourceGeoLocation.z);
		
sourceGeoLocation.z += 500.0;

glm::dvec3 startGridLocation = 
	geoReference->TransformLongitudeLatitudeHeightToUnreal(sourceGeoLocation);

FVector gridLocation(startGridLocation.x, startGridLocation.y, startGridLocation.z);
FRotator pawnRotation(0, -90, 0);
bool rotationSet = dynamicPawn->SetActorLocationAndRotation(gridLocation, pawnRotation);
geoReference->SetGeoreferenceOrigin(sourceGeoLocation);

MoveToSource

When the Enter key is pressed the MoveToSource function is called. I get the geospatial coordinates for the next source and then compute the bearing angle between the two just to move the camera direction to face the next source in transit. The FlyToLocationLongitudeLatitudeHeight method of the pawn will automatically start moving the camera along the path.

void ACesium3dTileApplication::MoveToSource(int sourceIndex) {
	if (sourceIndex < 0 || sourceIndex >= (int)_sources->Count()) {
		return;
	}

	glm::dvec3 targetGeoPoint = _sources->GetSourceInfo(sourceIndex)->GetUpperCenterGeoPoint();
	
	double bearing, distance;
	GeospatialFunctions::ComputeDistanceAndBearing(currentGeoLocation.X,
		currentGeoLocation.Y, targetGeoPoint.x, targetGeoPoint.y, distance, bearing);
	
	targetGeoPoint.z += 500;
	
	dynamicPawn->FlyToLocationLongitudeLatitudeHeight(targetGeoPoint, bearing, -30, false);
	geoReference->SetGeoreferenceOrigin(targetGeoPoint);
	
}

Updating the Sun

To keep the CesiumSunSky illuminating the camera location then it is updated via the Tick() function. The Unreal location is read from the pawn and if converted to geospatial with the longitude used to compute the time zone. If the time zone value has changed then it is the sun is updated. This will keep the camera location illuminated during flight.

void ACesium3dTileApplication::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	FVector currentPawnLocation = dynamicPawn->GetActorLocation();
	glm::dvec3 gridLocation(currentPawnLocation.X, currentPawnLocation.Y, currentPawnLocation.Z);

	glm::dvec3 currentGeoLocationDvec3 = 
		geoReference->TransformUnrealToLongitudeLatitudeHeight(gridLocation);

	currentGeoLocation = FVector(currentGeoLocationDvec3.x, currentGeoLocationDvec3.y, 
		currentGeoLocationDvec3.z);

	int timeZone = (int)floor((currentGeoLocationDvec3.x + 7.5) / 15.0);

	if (timeZone != _currentTimeZone) {
		_sunSky->SetTimeZone(timeZone);
		_sunSky->UpdateSun();
	}
}