From aed90eabf0e1919d02b97c1a1e676ae41382706e Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 28 Jul 2023 23:05:29 +1000 Subject: [PATCH 1/5] Deprecate GeoTransforms class. --- .../Private/CesiumGeoreference.cpp | 234 ++++++++---------- .../CesiumRuntime/Public/CesiumGeoreference.h | 31 +-- extern/cesium-native | 2 +- 3 files changed, 117 insertions(+), 150 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGeoreference.cpp b/Source/CesiumRuntime/Private/CesiumGeoreference.cpp index 82adc8c41..44f43a37a 100644 --- a/Source/CesiumRuntime/Private/CesiumGeoreference.cpp +++ b/Source/CesiumRuntime/Private/CesiumGeoreference.cpp @@ -4,6 +4,7 @@ #include "Camera/PlayerCameraManager.h" #include "CesiumActors.h" #include "CesiumCommon.h" +#include "CesiumGeospatial/Cartographic.h" #include "CesiumRuntime.h" #include "CesiumSubLevelComponent.h" #include "CesiumSubLevelSwitcherComponent.h" @@ -38,6 +39,23 @@ #include "Slate/SceneViewport.h" #endif +using namespace CesiumGeospatial; + +namespace { + +LocalHorizontalCoordinateSystem +createCoordinateSystem(const FVector& center, double scale) { + return LocalHorizontalCoordinateSystem( + VecMath::createVector3D(center), + LocalDirection::East, + LocalDirection::South, + LocalDirection::Up, + 1.0 / scale, + Ellipsoid::WGS84); +} + +} // namespace + /*static*/ ACesiumGeoreference* ACesiumGeoreference::GetDefaultGeoreference(const UObject* WorldContextObject) { UWorld* world = WorldContextObject->GetWorld(); @@ -119,10 +137,10 @@ FVector ACesiumGeoreference::GetOriginLongitudeLatitudeHeight() const { void ACesiumGeoreference::SetOriginLongitudeLatitudeHeight( const FVector& targetLongitudeLatitudeHeight) { - this->_setGeoreferenceOrigin( - targetLongitudeLatitudeHeight.X, - targetLongitudeLatitudeHeight.Y, - targetLongitudeLatitudeHeight.Z); + this->OriginLongitude = targetLongitudeLatitudeHeight.X; + this->OriginLatitude = targetLongitudeLatitudeHeight.Y; + this->OriginHeight = targetLongitudeLatitudeHeight.Z; + this->UpdateGeoreference(); } FVector ACesiumGeoreference::GetOriginEarthCenteredEarthFixed() const { @@ -205,47 +223,41 @@ void ACesiumGeoreference::SetShowLoadRadii(bool NewValue) { FVector ACesiumGeoreference::TransformLongitudeLatitudeHeightPositionToUnreal( const FVector& LongitudeLatitudeHeight) const { - glm::dvec3 ue = this->_geoTransforms.TransformLongitudeLatitudeHeightToUnreal( - glm::dvec3(CesiumActors::getWorldOrigin4D(this)), - VecMath::createVector3D(LongitudeLatitudeHeight)); - return FVector(ue.x, ue.y, ue.z); + return this->TransformEarthCenteredEarthFixedPositionToUnreal( + UCesiumWgs84Ellipsoid::LongitudeLatitudeHeightToEarthCenteredEarthFixed( + LongitudeLatitudeHeight)); } FVector ACesiumGeoreference::TransformUnrealPositionToLongitudeLatitudeHeight( const FVector& UnrealPosition) const { - glm::dvec3 llh = - this->_geoTransforms.TransformUnrealToLongitudeLatitudeHeight( - glm::dvec3(CesiumActors::getWorldOrigin4D(this)), - VecMath::createVector3D(UnrealPosition)); - return FVector(llh.x, llh.y, llh.z); + return UCesiumWgs84Ellipsoid:: + EarthCenteredEarthFixedToLongitudeLatitudeHeight( + this->TransformUnrealPositionToEarthCenteredEarthFixed( + UnrealPosition)); } FVector ACesiumGeoreference::TransformEarthCenteredEarthFixedPositionToUnreal( const FVector& EarthCenteredEarthFixedPosition) const { - glm::dvec3 ue = this->_geoTransforms.TransformEcefToUnreal( - glm::dvec3(CesiumActors::getWorldOrigin4D(this)), - VecMath::createVector3D(EarthCenteredEarthFixedPosition)); - return FVector(ue.x, ue.y, ue.z); + return VecMath::createVector(this->_coordinateSystem.ecefPositionToLocal( + VecMath::createVector3D(EarthCenteredEarthFixedPosition))); } FVector ACesiumGeoreference::TransformUnrealPositionToEarthCenteredEarthFixed( const FVector& UnrealPosition) const { - glm::dvec3 ecef = this->_geoTransforms.TransformUnrealToEcef( - glm::dvec3(CesiumActors::getWorldOrigin4D(this)), - glm::dvec3(UnrealPosition.X, UnrealPosition.Y, UnrealPosition.Z)); - return FVector(ecef.x, ecef.y, ecef.z); + return VecMath::createVector(this->_coordinateSystem.localPositionToEcef( + VecMath::createVector3D(UnrealPosition))); } FVector ACesiumGeoreference::TransformEarthCenteredEarthFixedDirectionToUnreal( const FVector& EarthCenteredEarthFixedDirection) const { - return this->_geoTransforms.GetEllipsoidCenteredToAbsoluteUnrealWorldMatrix() - .TransformVector(EarthCenteredEarthFixedDirection); + return VecMath::createVector(this->_coordinateSystem.ecefDirectionToLocal( + VecMath::createVector3D(EarthCenteredEarthFixedDirection))); } FVector ACesiumGeoreference::TransformUnrealDirectionToEarthCenteredEarthFixed( const FVector& UnrealDirection) const { - return this->_geoTransforms.GetAbsoluteUnrealWorldToEllipsoidCenteredMatrix() - .TransformVector(UnrealDirection); + return VecMath::createVector(this->_coordinateSystem.localDirectionToEcef( + VecMath::createVector3D(UnrealDirection))); } FRotator ACesiumGeoreference::TransformUnrealRotatorToEastSouthUp( @@ -264,24 +276,28 @@ FRotator ACesiumGeoreference::TransformEastSouthUpRotatorToUnreal( return FRotator(esuToUnreal.ToQuat() * EastSouthUpRotator.Quaternion()); } -const FMatrix& +FMatrix ACesiumGeoreference::ComputeUnrealToEarthCenteredEarthFixedTransformation() const { - return this->_geoTransforms.GetAbsoluteUnrealWorldToEllipsoidCenteredMatrix(); + return VecMath::createMatrix( + this->_coordinateSystem.getLocalToEcefTransformation()); } -const FMatrix& +FMatrix ACesiumGeoreference::ComputeEarthCenteredEarthFixedToUnrealTransformation() const { - return this->_geoTransforms.GetEllipsoidCenteredToAbsoluteUnrealWorldMatrix(); + return VecMath::createMatrix( + this->_coordinateSystem.getEcefToLocalTransformation()); } FMatrix ACesiumGeoreference::ComputeEastSouthUpToUnrealTransformation( const FVector& UnrealLocation) const { - glm::dmat4 esuToUe = this->_geoTransforms.ComputeEastSouthUpToUnreal( - glm::dvec3(CesiumActors::getWorldOrigin4D(this)), - glm::dvec3(UnrealLocation.X, UnrealLocation.Y, UnrealLocation.Z)); - return VecMath::createMatrix(esuToUe); + FVector ecef = + this->TransformUnrealPositionToEarthCenteredEarthFixed(UnrealLocation); + LocalHorizontalCoordinateSystem newLocal = + createCoordinateSystem(ecef, this->GetScale()); + return VecMath::createMatrix( + newLocal.computeTransformationToAnotherLocal(this->_coordinateSystem)); } FMatrix ACesiumGeoreference::ComputeUnrealToEastSouthUpTransformation( @@ -305,65 +321,31 @@ void ACesiumGeoreference::PlaceGeoreferenceOriginHere() { FEditorViewportClient* pEditorViewportClient = static_cast(pViewportClient); - FRotationTranslationMatrix fCameraTransform( + FRotator newViewRotation = this->TransformUnrealRotatorToEastSouthUp( pEditorViewportClient->GetViewRotation(), pEditorViewportClient->GetViewLocation()); - const FIntVector& originLocation = pWorld->OriginLocation; - - // TODO: optimize this, only need to transform the front direction and - // translation - - const FVector& viewLocation = pEditorViewportClient->GetViewLocation(); - glm::dvec4 translation = VecMath::add4D(viewLocation, originLocation); - - // camera local space to Unreal absolute world - glm::dmat4 cameraToAbsolute = - VecMath::createMatrix4D(fCameraTransform, translation); // camera local space to ECEF - glm::dmat4 cameraToECEF = - this->_geoTransforms - .GetAbsoluteUnrealWorldToEllipsoidCenteredTransform() * - cameraToAbsolute; + FVector cameraEcefPosition = + this->TransformUnrealPositionToEarthCenteredEarthFixed( + pEditorViewportClient->GetViewLocation()); // Long/Lat/Height camera location, in degrees/meters (also our new target // georeference origin) When the location is too close to the center of the // earth, the result will be (0,0,0) - glm::dvec3 targetGeoreferenceOrigin = - _geoTransforms.TransformEcefToLongitudeLatitudeHeight( - glm::dvec3(cameraToECEF[3])); - - this->_setGeoreferenceOrigin( - targetGeoreferenceOrigin.x, - targetGeoreferenceOrigin.y, - targetGeoreferenceOrigin.z); - - glm::dmat4 absoluteToRelativeWorld = VecMath::createTranslationMatrix4D( - -originLocation.X, - -originLocation.Y, - -originLocation.Z, - 1.0); + this->SetOriginEarthCenteredEarthFixed(cameraEcefPosition); // TODO: check for degeneracy ? - glm::dmat4 newCameraTransform = - absoluteToRelativeWorld * - this->_geoTransforms - .GetEllipsoidCenteredToAbsoluteUnrealWorldTransform() * - cameraToECEF; - glm::dvec3 cameraFront = glm::normalize(glm::dvec3(newCameraTransform[0])); - glm::dvec3 cameraRight = - glm::normalize(glm::cross(glm::dvec3(0.0, 0.0, 1.0), cameraFront)); - glm::dvec3 cameraUp = glm::normalize(glm::cross(cameraFront, cameraRight)); + FVector cameraFront = newViewRotation.RotateVector(FVector::XAxisVector); + FVector cameraRight = + FVector::CrossProduct(FVector::ZAxisVector, cameraFront).GetSafeNormal(); + FVector cameraUp = + FVector::CrossProduct(cameraFront, cameraRight).GetSafeNormal(); pEditorViewportClient->SetViewRotation( - FMatrix( - FVector(cameraFront.x, cameraFront.y, cameraFront.z), - FVector(cameraRight.x, cameraRight.y, cameraRight.z), - FVector(cameraUp.x, cameraUp.y, cameraUp.z), - FVector::ZeroVector) + FMatrix(cameraFront, cameraRight, cameraUp, FVector::ZeroVector) .Rotator()); - pEditorViewportClient->SetViewLocation( - FVector(-originLocation.X, -originLocation.Y, -originLocation.Z)); + pEditorViewportClient->SetViewLocation(FVector::ZeroVector); } void ACesiumGeoreference::_showSubLevelLoadRadii() const { @@ -374,8 +356,7 @@ void ACesiumGeoreference::_showSubLevelLoadRadii() const { if (!this->ShowLoadRadii) { return; } - const glm::dvec4 originLocation = - glm::dvec4(VecMath::createVector3D(world->OriginLocation), 1.0); + for (const auto& pLevelWeak : this->SubLevelSwitcher->GetRegisteredSubLevels()) { ALevelInstance* pLevel = pLevelWeak.Get(); @@ -385,12 +366,6 @@ void ACesiumGeoreference::_showSubLevelLoadRadii() const { UCesiumSubLevelComponent* pComponent = pLevel->FindComponentByClass(); - glm::dvec3 levelECEF = - _geoTransforms.TransformLongitudeLatitudeHeightToEcef(glm::dvec3( - pComponent->GetOriginLongitude(), - pComponent->GetOriginLatitude(), - pComponent->GetOriginHeight())); - FVector center = this->TransformLongitudeLatitudeHeightPositionToUnreal(FVector( pComponent->GetOriginLongitude(), @@ -427,7 +402,7 @@ void ACesiumGeoreference::Serialize(FArchive& Ar) { // Recompute derived values on load. if (Ar.IsLoading()) { - this->_updateGeoTransforms(); + this->_updateCoordinateSystem(); } } @@ -641,9 +616,7 @@ FVector ACesiumGeoreference::TransformEcefToLongitudeLatitudeHeight( FMatrix ACesiumGeoreference::ComputeEastNorthUpToEcef(const FVector& ecef) const { - glm::dmat3 enuToEcef = this->_geoTransforms.ComputeEastNorthUpToEcef( - glm::dvec3(ecef.X, ecef.Y, ecef.Z)); - return VecMath::createMatrix(enuToEcef); + return UCesiumWgs84Ellipsoid::EastNorthUpToEarthCenteredEarthFixed(ecef); } ACesiumGeoreference::ACesiumGeoreference() : AActor(), _geoTransforms() { @@ -661,7 +634,7 @@ ACesiumGeoreference::ACesiumGeoreference() : AActor(), _geoTransforms() { } void ACesiumGeoreference::UpdateGeoreference() { - this->_updateGeoTransforms(); + this->_updateCoordinateSystem(); // If we're in a sub-level, update its origin as well. UCesiumSubLevelSwitcherComponent* pSwitcher = this->SubLevelSwitcher; @@ -689,20 +662,18 @@ void ACesiumGeoreference::UpdateGeoreference() { OnGeoreferenceUpdated.Broadcast(); } +const GeoTransforms& ACesiumGeoreference::GetGeoTransforms() const noexcept { + // Because GeoTransforms is deprecated, we only lazily update it. + this->_geoTransforms = GeoTransforms( + Ellipsoid::WGS84, + glm::dvec3(this->_coordinateSystem.getLocalToEcefTransformation()[3]), + this->GetScale() / 100.0); + return this->_geoTransforms; +} + FName ACesiumGeoreference::DEFAULT_GEOREFERENCE_TAG = FName("DEFAULT_GEOREFERENCE"); -void ACesiumGeoreference::_setGeoreferenceOrigin( - double targetLongitude, - double targetLatitude, - double targetHeight) { - this->OriginLongitude = targetLongitude; - this->OriginLatitude = targetLatitude; - this->OriginHeight = targetHeight; - - this->UpdateGeoreference(); -} - bool ACesiumGeoreference::_updateSublevelState() { const TArray>& sublevels = this->SubLevelSwitcher->GetRegisteredSubLevels(); @@ -722,17 +693,13 @@ bool ACesiumGeoreference::_updateSublevelState() { const FMinimalViewInfo& pov = this->SubLevelCamera->ViewTarget.POV; const FVector& cameraLocation = pov.Location; - glm::dvec4 cameraAbsolute = VecMath::add4D(cameraLocation, originLocation); - - glm::dmat4 ueGeoreferenceToUeWorld = - VecMath::createMatrix4D(this->GetActorTransform().ToMatrixWithScale()); + // Transform camera from World to Georeference local frame + FVector cameraRelativeToGeoreference = + this->GetActorTransform().TransformPosition(cameraLocation); - const glm::dmat4& cesiumGeoreferenceToUeGeoreference = - this->_geoTransforms.GetEllipsoidCenteredToAbsoluteUnrealWorldTransform(); - glm::dmat4 unrealWorldToCesiumGeoreference = glm::affineInverse( - ueGeoreferenceToUeWorld * cesiumGeoreferenceToUeGeoreference); - glm::dvec3 cameraECEF = - glm::dvec3(unrealWorldToCesiumGeoreference * cameraAbsolute); + // Transform camera from Georeference local frame to ECEF + FVector cameraEcef = this->TransformUnrealPositionToEarthCenteredEarthFixed( + cameraRelativeToGeoreference); ALevelInstance* pClosestActiveLevel = nullptr; double closestLevelDistance = std::numeric_limits::max(); @@ -750,13 +717,14 @@ bool ACesiumGeoreference::_updateSublevelState() { if (!pComponent->GetEnabled()) continue; - glm::dvec3 levelECEF = - _geoTransforms.TransformLongitudeLatitudeHeightToEcef(glm::dvec3( - pComponent->GetOriginLongitude(), - pComponent->GetOriginLatitude(), - pComponent->GetOriginHeight())); + FVector levelEcef = + UCesiumWgs84Ellipsoid::LongitudeLatitudeHeightToEarthCenteredEarthFixed( + FVector( + pComponent->GetOriginLongitude(), + pComponent->GetOriginLatitude(), + pComponent->GetOriginHeight())); - double levelDistance = glm::length(levelECEF - cameraECEF); + double levelDistance = FVector::Distance(levelEcef, cameraEcef); if (levelDistance < pComponent->GetLoadRadius() && levelDistance < closestLevelDistance) { pClosestActiveLevel = pCurrent; @@ -769,19 +737,25 @@ bool ACesiumGeoreference::_updateSublevelState() { return pClosestActiveLevel != nullptr; } -void ACesiumGeoreference::_updateGeoTransforms() { - glm::dvec3 center(0.0, 0.0, 0.0); +void ACesiumGeoreference::_updateCoordinateSystem() { if (this->OriginPlacement == EOriginPlacement::CartographicOrigin) { - center = _geoTransforms.TransformLongitudeLatitudeHeightToEcef(glm::dvec3( - this->OriginLongitude, - this->OriginLatitude, - this->OriginHeight)); + FVector origin = this->GetOriginLongitudeLatitudeHeight(); + this->_coordinateSystem = createCoordinateSystem( + this->GetOriginEarthCenteredEarthFixed(), + this->GetScale()); + } else { + // In True Origin mode, we want a coordinate system that: + // 1. Is at the origin, + // 2. Inverts Y to create a left-handed coordinate system, and + // 3. Uses the georeference's scale + double scale = 1.0 / this->GetScale(); + glm::dmat4 localToEcef( + glm::dvec4(scale, 0.0, 0.0, 0.0), + glm::dvec4(0.0, -scale, 0.0, 0.0), + glm::dvec4(0.0, 0.0, scale, 0.0), + glm::dvec4(0.0, 0.0, 0.0, 1.0)); + this->_coordinateSystem = LocalHorizontalCoordinateSystem(localToEcef); } - - this->_geoTransforms = GeoTransforms( - CesiumGeospatial::Ellipsoid::WGS84, - center, - this->Scale / 100.0); } bool ACesiumGeoreference::_shouldManageSubLevels() const { diff --git a/Source/CesiumRuntime/Public/CesiumGeoreference.h b/Source/CesiumRuntime/Public/CesiumGeoreference.h index de9359562..24c9ea5df 100644 --- a/Source/CesiumRuntime/Public/CesiumGeoreference.h +++ b/Source/CesiumRuntime/Public/CesiumGeoreference.h @@ -2,6 +2,7 @@ #pragma once +#include "CesiumGeospatial/LocalHorizontalCoordinateSystem.h" #include "CesiumSubLevel.h" #include "Containers/UnrealString.h" #include "CoreMinimal.h" @@ -498,7 +499,7 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { BlueprintPure, Category = "Cesium", meta = (ReturnDisplayName = "UnrealToEarthCenteredEarthFixedMatrix")) - const FMatrix& ComputeUnrealToEarthCenteredEarthFixedTransformation() const; + FMatrix ComputeUnrealToEarthCenteredEarthFixedTransformation() const; /** * Computes the transformation matrix from the Earth-Centered, Earth-Fixed @@ -512,7 +513,7 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { BlueprintPure, Category = "Cesium", meta = (ReturnDisplayName = "EarthCenteredEarthFixedToUnrealMatrix")) - const FMatrix& ComputeEarthCenteredEarthFixedToUnrealTransformation() const; + FMatrix ComputeEarthCenteredEarthFixedToUnrealTransformation() const; /** * Computes the matrix that transforms from an East-South-Up frame centered at @@ -618,6 +619,11 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { #pragma region Obsolete +public: + [[deprecated( + "Use transformation functions on ACesiumGeoreference and UCesiumWgs84Ellipsoid instead.")]] const GeoTransforms& + GetGeoTransforms() const noexcept; + private: PRAGMA_DISABLE_DEPRECATION_WARNINGS UPROPERTY( @@ -687,15 +693,6 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { */ void UpdateGeoreference(); - /** - * Returns the GeoTransforms that offers the same conversion - * functions as this class, but performs the computations - * in double precision. - */ - const GeoTransforms& GetGeoTransforms() const noexcept { - return _geoTransforms; - } - private: /** * A tag that is assigned to Georeferences when they are created @@ -703,17 +700,13 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { */ static FName DEFAULT_GEOREFERENCE_TAG; - GeoTransforms _geoTransforms; + mutable GeoTransforms _geoTransforms; + CesiumGeospatial::LocalHorizontalCoordinateSystem _coordinateSystem{ + glm::dmat4(1.0)}; UPROPERTY() UCesiumSubLevelSwitcherComponent* SubLevelSwitcher; - // TODO: add option to set georeference directly from ECEF - void _setGeoreferenceOrigin( - double targetLongitude, - double targetLatitude, - double targetHeight); - /** * @brief Updates the load state of sub-levels. * @@ -729,7 +722,7 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { * Updates _geoTransforms based on the current ellipsoid and center, and * returns the old transforms. */ - void _updateGeoTransforms(); + void _updateCoordinateSystem(); /** * Determines if this Georeference should manage sub-level switching. diff --git a/extern/cesium-native b/extern/cesium-native index f69be7d53..ef58d31fa 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit f69be7d53ae04833c0030e07b401695b55f3a54a +Subproject commit ef58d31fa0741ba24de745067051c475a1ada828 From c4cc328a9e3a351827ef73a6041fac9b6d29d0f1 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Mon, 31 Jul 2023 12:52:09 +1000 Subject: [PATCH 2/5] Eliminate uses of now-deprecated GeoTransforms. --- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 63 +++++++++---------- .../Private/CesiumGlobeAnchorComponent.cpp | 63 ++++++++++++------- Source/CesiumRuntime/Private/CesiumSunSky.cpp | 7 +-- .../Private/GlobeAwareDefaultPawn.cpp | 16 ++--- .../CesiumRuntime/Public/CesiumGeoreference.h | 5 ++ 5 files changed, 81 insertions(+), 73 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index a422e777c..e59818a00 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -20,6 +20,7 @@ #include "CesiumCustomVersion.h" #include "CesiumGeospatial/Cartographic.h" #include "CesiumGeospatial/Ellipsoid.h" +#include "CesiumGeospatial/GlobeTransforms.h" #include "CesiumGltf/ImageCesium.h" #include "CesiumGltf/Ktx2TranscodeTargets.h" #include "CesiumGltfComponent.h" @@ -474,13 +475,10 @@ void ACesium3DTileset::OnFocusEditorViewportOnThis() { *this->GetName()); struct CalculateECEFCameraPosition { - - const GeoTransforms& localGeoTransforms; - glm::dvec3 operator()(const CesiumGeometry::BoundingSphere& sphere) { const glm::dvec3& center = sphere.getCenter(); glm::dmat4 ENU = - glm::dmat4(localGeoTransforms.ComputeEastNorthUpToEcef(center)); + CesiumGeospatial::GlobeTransforms::eastNorthUpToFixedFrame(center); glm::dvec3 offset = sphere.getRadius() * glm::normalize( @@ -493,7 +491,7 @@ void ACesium3DTileset::OnFocusEditorViewportOnThis() { operator()(const CesiumGeometry::OrientedBoundingBox& orientedBoundingBox) { const glm::dvec3& center = orientedBoundingBox.getCenter(); glm::dmat4 ENU = - glm::dmat4(localGeoTransforms.ComputeEastNorthUpToEcef(center)); + CesiumGeospatial::GlobeTransforms::eastNorthUpToFixedFrame(center); const glm::dmat3& halfAxes = orientedBoundingBox.getHalfAxes(); glm::dvec3 offset = glm::length(halfAxes[0] + halfAxes[1] + halfAxes[2]) * @@ -529,39 +527,37 @@ void ACesium3DTileset::OnFocusEditorViewportOnThis() { const Cesium3DTilesSelection::BoundingVolume& boundingVolume = pRootTile->getBoundingVolume(); + ACesiumGeoreference* pGeoreference = this->ResolveGeoreference(); + // calculate unreal camera position const glm::dmat4& transform = this->GetCesiumTilesetToUnrealRelativeWorldTransform(); - glm::dvec3 ecefCameraPosition = std::visit( - CalculateECEFCameraPosition{ - this->ResolveGeoreference()->GetGeoTransforms()}, - boundingVolume); - glm::dvec3 unrealCameraPosition = - glm::dvec3(transform * glm::dvec4(ecefCameraPosition, 1.0)); + glm::dvec3 ecefCameraPosition = + std::visit(CalculateECEFCameraPosition{}, boundingVolume); + FVector unrealCameraPosition = + pGeoreference->TransformEarthCenteredEarthFixedPositionToUnreal( + VecMath::createVector(ecefCameraPosition)); // calculate unreal camera orientation glm::dvec3 ecefCenter = Cesium3DTilesSelection::getBoundingVolumeCenter(boundingVolume); - glm::dvec3 unrealCenter = glm::dvec3(transform * glm::dvec4(ecefCenter, 1.0)); - glm::dvec3 unrealCameraFront = - glm::normalize(unrealCenter - unrealCameraPosition); - glm::dvec3 unrealCameraRight = - glm::normalize(glm::cross(glm::dvec3(0.0, 0.0, 1.0), unrealCameraFront)); - glm::dvec3 unrealCameraUp = - glm::normalize(glm::cross(unrealCameraFront, unrealCameraRight)); - FRotator cameraRotator = - FMatrix( - FVector( - unrealCameraFront.x, - unrealCameraFront.y, - unrealCameraFront.z), - FVector( - unrealCameraRight.x, - unrealCameraRight.y, - unrealCameraRight.z), - FVector(unrealCameraUp.x, unrealCameraUp.y, unrealCameraUp.z), - FVector(0.0f, 0.0f, 0.0f)) - .Rotator(); + FVector unrealCenter = + pGeoreference->TransformEarthCenteredEarthFixedPositionToUnreal( + VecMath::createVector(ecefCenter)); + FVector unrealCameraFront = + (unrealCenter - unrealCameraPosition).GetSafeNormal(); + FVector unrealCameraRight = + FVector::CrossProduct(FVector::ZAxisVector, unrealCameraFront) + .GetSafeNormal(); + FVector unrealCameraUp = + FVector::CrossProduct(unrealCameraFront, unrealCameraRight) + .GetSafeNormal(); + FRotator cameraRotator = FMatrix( + unrealCameraFront, + unrealCameraRight, + unrealCameraUp, + FVector::ZeroVector) + .Rotator(); // Update all viewports. for (FLevelEditorViewportClient* LinkedViewportClient : @@ -571,10 +567,7 @@ void ACesium3DTileset::OnFocusEditorViewportOnThis() { FViewportCameraTransform& ViewTransform = LinkedViewportClient->GetViewTransform(); LinkedViewportClient->SetViewRotation(cameraRotator); - LinkedViewportClient->SetViewLocation(FVector( - unrealCameraPosition.x, - unrealCameraPosition.y, - unrealCameraPosition.z)); + LinkedViewportClient->SetViewLocation(unrealCameraPosition); LinkedViewportClient->Invalidate(); } } diff --git a/Source/CesiumRuntime/Private/CesiumGlobeAnchorComponent.cpp b/Source/CesiumRuntime/Private/CesiumGlobeAnchorComponent.cpp index 0aae8fcbf..d71380f7f 100644 --- a/Source/CesiumRuntime/Private/CesiumGlobeAnchorComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGlobeAnchorComponent.cpp @@ -4,6 +4,7 @@ #include "CesiumActors.h" #include "CesiumCustomVersion.h" #include "CesiumGeoreference.h" +#include "CesiumGeospatial/GlobeTransforms.h" #include "CesiumRuntime.h" #include "CesiumTransforms.h" #include "CesiumWgs84Ellipsoid.h" @@ -148,8 +149,8 @@ void UCesiumGlobeAnchorComponent::SnapToEastSouthUp() { // Compute the desired new orientation. glm::dmat3 newOrientation = - this->ResolvedGeoreference->GetGeoTransforms().ComputeEastNorthUpToEcef( - glm::dvec3(translation)) * + glm::dmat3(CesiumGeospatial::GlobeTransforms::eastNorthUpToFixedFrame( + glm::dvec3(translation))) * glm::dmat3(CesiumTransforms::unrealToOrFromCesium); // Scale the new orientation @@ -433,11 +434,18 @@ void UCesiumGlobeAnchorComponent::_onActorTransformChanged( // Compute the surface normal rotation between the old and new positions. const glm::dvec3 newGlobePosition = glm::dvec3(newGlobeTransform[3]); + + const glm::dmat3 ecefToUnreal = + glm::dmat3(this->ResolvedGeoreference->getCoordinateSystem() + .getEcefToLocalTransformation()); + const glm::dvec3 oldEllipsoidNormalUnreal = glm::normalize( + ecefToUnreal * CesiumGeospatial::Ellipsoid::WGS84.geodeticSurfaceNormal( + oldGlobePosition)); + const glm::dvec3 newEllipsoidNormalUnreal = glm::normalize( + ecefToUnreal * CesiumGeospatial::Ellipsoid::WGS84.geodeticSurfaceNormal( + newGlobePosition)); const glm::dquat ellipsoidNormalRotation = - this->ResolvedGeoreference->GetGeoTransforms() - .ComputeSurfaceNormalRotationUnreal( - oldGlobePosition, - newGlobePosition); + glm::rotation(oldEllipsoidNormalUnreal, newEllipsoidNormalUnreal); // Adjust the new rotation by the surface normal rotation const glm::dquat rotation = VecMath::createQuaternion( @@ -515,8 +523,8 @@ UCesiumGlobeAnchorComponent::_updateGlobeTransformFromActorTransform() { // Convert to ECEF const glm::dmat4& absoluteUnrealToEcef = - this->ResolvedGeoreference->GetGeoTransforms() - .GetAbsoluteUnrealWorldToEllipsoidCenteredTransform(); + this->ResolvedGeoreference->getCoordinateSystem() + .getLocalToEcefTransformation(); this->_actorToECEF = absoluteUnrealToEcef * actorTransform; this->_actorToECEFIsValid = true; @@ -565,12 +573,12 @@ FTransform UCesiumGlobeAnchorComponent::_updateActorTransformFromGlobeTransform( return pOwnerRoot->GetRelativeTransform(); } - const GeoTransforms& geoTransforms = - this->ResolveGeoreference()->GetGeoTransforms(); + const CesiumGeospatial::LocalHorizontalCoordinateSystem& coordinateSystem = + this->ResolveGeoreference()->getCoordinateSystem(); // Transform ECEF to UE absolute world const glm::dmat4& ecefToAbsoluteUnreal = - geoTransforms.GetEllipsoidCenteredToAbsoluteUnrealWorldTransform(); + coordinateSystem.getEcefToLocalTransformation(); glm::dmat4 actorToUnreal = ecefToAbsoluteUnreal * this->_actorToECEF; // Transform UE absolute world to UE relative world @@ -623,10 +631,9 @@ const glm::dmat4& UCesiumGlobeAnchorComponent::_setGlobeTransform( // position on the globe. // Compute the surface normal rotation between the old and new positions. - const glm::dquat ellipsoidNormalRotation = - this->ResolveGeoreference() - ->GetGeoTransforms() - .ComputeSurfaceNormalRotation(oldPosition, newPosition); + const glm::dquat ellipsoidNormalRotation = glm::rotation( + CesiumGeospatial::Ellipsoid::WGS84.geodeticSurfaceNormal(oldPosition), + CesiumGeospatial::Ellipsoid::WGS84.geodeticSurfaceNormal(newPosition)); // Adjust the new rotation by the surface normal rotation glm::dmat3 newRotation = @@ -698,8 +705,11 @@ void UCesiumGlobeAnchorComponent::_applyCartographicProperties() { glm::dmat4 transform = this->_actorToECEF; glm::dvec3 newEcef = - pGeoreference->GetGeoTransforms().TransformLongitudeLatitudeHeightToEcef( - glm::dvec3(this->Longitude, this->Latitude, this->Height)); + CesiumGeospatial::Ellipsoid::WGS84.cartographicToCartesian( + CesiumGeospatial::Cartographic::fromDegrees( + this->Longitude, + this->Latitude, + this->Height)); transform[3] = glm::dvec4(newEcef, 1.0); this->_setGlobeTransform(transform); @@ -721,11 +731,18 @@ void UCesiumGlobeAnchorComponent::_updateCartographicProperties() { *this->GetName()); } - glm::dvec3 llh = - pGeoreference->GetGeoTransforms().TransformEcefToLongitudeLatitudeHeight( + std::optional llh = + CesiumGeospatial::Ellipsoid::WGS84.cartesianToCartographic( glm::dvec3(this->_actorToECEF[3])); - - this->Longitude = llh.x; - this->Latitude = llh.y; - this->Height = llh.z; + if (llh) { + this->Longitude = CesiumUtility::Math::radiansToDegrees(llh->longitude); + this->Latitude = CesiumUtility::Math::radiansToDegrees(llh->latitude); + this->Height = llh->height; + } else { + // Too close to the center of the Earth to compute + // Longitude/Latitude/Height. So use a default. + this->Longitude = 0.0; + this->Latitude = 0.0; + this->Height = 0.0; + } } diff --git a/Source/CesiumRuntime/Private/CesiumSunSky.cpp b/Source/CesiumRuntime/Private/CesiumSunSky.cpp index 991d30999..c566355a1 100644 --- a/Source/CesiumRuntime/Private/CesiumSunSky.cpp +++ b/Source/CesiumRuntime/Private/CesiumSunSky.cpp @@ -525,10 +525,9 @@ void ACesiumSunSky::UpdateAtmosphereRadius() { } else { // Find the ellipsoid radius 100m below the surface at this location. See // the comment at the top of this file. - glm::dvec3 ecef = this->GetGeoreference() - ->GetGeoTransforms() - .TransformLongitudeLatitudeHeightToEcef( - glm::dvec3(llh.X, llh.Y, -100.0)); + glm::dvec3 ecef = + CesiumGeospatial::Ellipsoid::WGS84.cartographicToCartesian( + CesiumGeospatial::Cartographic::fromDegrees(llh.X, llh.Y, -100.0)); double minRadius = glm::length(ecef); if (llh.Z / 1000.0 < this->InscribedGroundThreshold) { diff --git a/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp b/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp index 8d8920ce3..7fc69925b 100644 --- a/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp +++ b/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp @@ -45,14 +45,10 @@ void AGlobeAwareDefaultPawn::MoveUp_World(float Val) { return; } - glm::dvec4 upEcef( - this->_ellipsoid.geodeticSurfaceNormal( - VecMath::createVector3D(this->GlobeAnchor->GetECEF())), - 0.0); - glm::dvec4 up = this->GlobeAnchor->ResolveGeoreference() - ->GetGeoTransforms() - .GetEllipsoidCenteredToAbsoluteUnrealWorldTransform() * - upEcef; + FVector upEcef = UCesiumWgs84Ellipsoid::GeodeticSurfaceNormal( + this->GlobeAnchor->GetECEF()); + FVector up = this->GlobeAnchor->ResolveGeoreference() + ->TransformEarthCenteredEarthFixedDirectionToUnreal(upEcef); FTransform transform{}; USceneComponent* pRootComponent = this->GetRootComponent(); @@ -63,9 +59,7 @@ void AGlobeAwareDefaultPawn::MoveUp_World(float Val) { } } - this->_moveAlongVector( - transform.TransformVector(FVector(up.x, up.y, up.z)), - Val); + this->_moveAlongVector(transform.TransformVector(up), Val); } FRotator AGlobeAwareDefaultPawn::GetViewRotation() const { diff --git a/Source/CesiumRuntime/Public/CesiumGeoreference.h b/Source/CesiumRuntime/Public/CesiumGeoreference.h index 24c9ea5df..f39206f15 100644 --- a/Source/CesiumRuntime/Public/CesiumGeoreference.h +++ b/Source/CesiumRuntime/Public/CesiumGeoreference.h @@ -693,6 +693,11 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { */ void UpdateGeoreference(); + const CesiumGeospatial::LocalHorizontalCoordinateSystem& + getCoordinateSystem() const noexcept { + return this->_coordinateSystem; + } + private: /** * A tag that is assigned to Georeferences when they are created From 7d6ae59d54be9d7d24bd4058e6b2be36b47a9ddc Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 2 Aug 2023 10:51:36 +1000 Subject: [PATCH 3/5] Use latest local-horizontal-from-transform branch of cesium-native. --- extern/cesium-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/cesium-native b/extern/cesium-native index 172ac5ddc..37f0a4569 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit 172ac5ddcce602c8b268ad342639554dea2f6004 +Subproject commit 37f0a4569de7b9e1f7631a005881d246ab098602 From ffad7be656374bf444252492efe04e5edea053e7 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 2 Aug 2023 11:13:41 +1000 Subject: [PATCH 4/5] Another try at using the latest local-horizontal-from-transform branch of cesium-native. --- extern/cesium-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/cesium-native b/extern/cesium-native index 37f0a4569..ada43f095 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit 37f0a4569de7b9e1f7631a005881d246ab098602 +Subproject commit ada43f09505061067f5ebf7aa445f7133122b3f4 From a2b94a7f87b133c74ded165439ff998a1fc03e2d Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 14 Sep 2023 11:45:30 +1000 Subject: [PATCH 5/5] Improvements from review. --- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 2 - .../Private/CesiumGeoreference.cpp | 7 +-- .../Private/GlobeAwareDefaultPawn.cpp | 55 ++++++++++++------- .../CesiumRuntime/Public/CesiumGeoreference.h | 3 +- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 35698e2cf..7d9719203 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -530,8 +530,6 @@ void ACesium3DTileset::OnFocusEditorViewportOnThis() { ACesiumGeoreference* pGeoreference = this->ResolveGeoreference(); // calculate unreal camera position - const glm::dmat4& transform = - this->GetCesiumTilesetToUnrealRelativeWorldTransform(); glm::dvec3 ecefCameraPosition = std::visit(CalculateECEFCameraPosition{}, boundingVolume); FVector unrealCameraPosition = diff --git a/Source/CesiumRuntime/Private/CesiumGeoreference.cpp b/Source/CesiumRuntime/Private/CesiumGeoreference.cpp index 22a76f978..29057358f 100644 --- a/Source/CesiumRuntime/Private/CesiumGeoreference.cpp +++ b/Source/CesiumRuntime/Private/CesiumGeoreference.cpp @@ -621,7 +621,7 @@ ACesiumGeoreference::ComputeEastNorthUpToEcef(const FVector& ecef) const { return UCesiumWgs84Ellipsoid::EastNorthUpToEarthCenteredEarthFixed(ecef); } -ACesiumGeoreference::ACesiumGeoreference() : AActor(), _geoTransforms() { +ACesiumGeoreference::ACesiumGeoreference() : AActor() { PrimaryActorTick.bCanEverTick = true; this->Root = CreateDefaultSubobject(TEXT("Root")); @@ -664,13 +664,12 @@ void ACesiumGeoreference::UpdateGeoreference() { OnGeoreferenceUpdated.Broadcast(); } -const GeoTransforms& ACesiumGeoreference::GetGeoTransforms() const noexcept { +GeoTransforms ACesiumGeoreference::GetGeoTransforms() const noexcept { // Because GeoTransforms is deprecated, we only lazily update it. - this->_geoTransforms = GeoTransforms( + return GeoTransforms( Ellipsoid::WGS84, glm::dvec3(this->_coordinateSystem.getLocalToEcefTransformation()[3]), this->GetScale() / 100.0); - return this->_geoTransforms; } FName ACesiumGeoreference::DEFAULT_GEOREFERENCE_TAG = diff --git a/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp b/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp index 7fc69925b..6fc947f95 100644 --- a/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp +++ b/Source/CesiumRuntime/Private/GlobeAwareDefaultPawn.cpp @@ -41,14 +41,19 @@ void AGlobeAwareDefaultPawn::MoveForward(float Val) { } void AGlobeAwareDefaultPawn::MoveUp_World(float Val) { - if (Val == 0.0f || !IsValid(this->GlobeAnchor)) { + if (Val == 0.0f) { + return; + } + + ACesiumGeoreference* pGeoreference = this->GetGeoreference(); + if (!IsValid(pGeoreference)) { return; } FVector upEcef = UCesiumWgs84Ellipsoid::GeodeticSurfaceNormal( this->GlobeAnchor->GetECEF()); - FVector up = this->GlobeAnchor->ResolveGeoreference() - ->TransformEarthCenteredEarthFixedDirectionToUnreal(upEcef); + FVector up = + pGeoreference->TransformEarthCenteredEarthFixedDirectionToUnreal(upEcef); FTransform transform{}; USceneComponent* pRootComponent = this->GetRootComponent(); @@ -67,6 +72,11 @@ FRotator AGlobeAwareDefaultPawn::GetViewRotation() const { return this->GetActorRotation(); } + ACesiumGeoreference* pGeoreference = this->GetGeoreference(); + if (!pGeoreference) { + return this->GetActorRotation(); + } + // The control rotation is expressed in a left-handed East-South-Up (ESU) // coordinate system: // * Yaw: Clockwise from East: 0 is East, 90 degrees is @@ -90,8 +100,7 @@ FRotator AGlobeAwareDefaultPawn::GetViewRotation() const { FVector globePosition = transform.InverseTransformPosition(this->GetPawnViewLocation()); FMatrix esuAdjustmentMatrix = - this->GetGeoreference()->ComputeEastSouthUpToUnrealTransformation( - globePosition) * + pGeoreference->ComputeEastSouthUpToUnrealTransformation(globePosition) * transform.ToMatrixNoScale(); return FRotator(esuAdjustmentMatrix.ToQuat() * localRotation.Quaternion()); @@ -166,6 +175,10 @@ void AGlobeAwareDefaultPawn::FlyToLocationECEF( return; } + if (!IsValid(this->GetGeoreference())) { + return; + } + PitchAtDestination = glm::clamp(PitchAtDestination, -89.99, 89.99); // Compute source location in ECEF glm::dvec3 ECEFSource = VecMath::createVector3D(this->GlobeAnchor->GetECEF()); @@ -256,13 +269,6 @@ void AGlobeAwareDefaultPawn::FlyToLocationLongitudeLatitudeHeight( double PitchAtDestination, bool CanInterruptByMoving) { - if (!IsValid(this->GetGeoreference())) { - UE_LOG( - LogCesium, - Warning, - TEXT("GlobeAwareDefaultPawn %s does not have a valid Georeference"), - *this->GetName()); - } FVector ecef = UCesiumWgs84Ellipsoid::LongitudeLatitudeHeightToEarthCenteredEarthFixed( VecMath::createVector(LongitudeLatitudeHeightDestination)); @@ -290,13 +296,7 @@ void AGlobeAwareDefaultPawn::FlyToLocationLongitudeLatitudeHeight( bool AGlobeAwareDefaultPawn::ShouldTickIfViewportsOnly() const { return true; } void AGlobeAwareDefaultPawn::_handleFlightStep(float DeltaSeconds) { - if (!IsValid(this->GlobeAnchor)) { - UE_LOG( - LogCesium, - Warning, - TEXT( - "GlobeAwareDefaultPawn %s does not have a valid GeoreferenceComponent"), - *this->GetName()); + if (!IsValid(this->GetGeoreference())) { return; } @@ -386,11 +386,24 @@ ACesiumGeoreference* AGlobeAwareDefaultPawn::GetGeoreference() const { UE_LOG( LogCesium, Error, - TEXT("GlobeAwareDefaultPawn %s does not have a GlobeAnchorComponent"), + TEXT( + "GlobeAwareDefaultPawn %s does not have a valid GlobeAnchorComponent."), *this->GetName()); return nullptr; } - return this->GlobeAnchor->ResolveGeoreference(); + + ACesiumGeoreference* pGeoreference = this->GlobeAnchor->ResolveGeoreference(); + if (!IsValid(pGeoreference)) { + UE_LOG( + LogCesium, + Error, + TEXT( + "GlobeAwareDefaultPawn %s does not have a valie CesiumGeoreference."), + *this->GetName()); + pGeoreference = nullptr; + } + + return pGeoreference; } void AGlobeAwareDefaultPawn::_moveAlongViewAxis(EAxis::Type axis, double Val) { diff --git a/Source/CesiumRuntime/Public/CesiumGeoreference.h b/Source/CesiumRuntime/Public/CesiumGeoreference.h index 1c8e8182d..b628fb64f 100644 --- a/Source/CesiumRuntime/Public/CesiumGeoreference.h +++ b/Source/CesiumRuntime/Public/CesiumGeoreference.h @@ -626,7 +626,7 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { public: [[deprecated( - "Use transformation functions on ACesiumGeoreference and UCesiumWgs84Ellipsoid instead.")]] const GeoTransforms& + "Use transformation functions on ACesiumGeoreference and UCesiumWgs84Ellipsoid instead.")]] GeoTransforms GetGeoTransforms() const noexcept; private: @@ -709,7 +709,6 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor { */ static FName DEFAULT_GEOREFERENCE_TAG; - mutable GeoTransforms _geoTransforms; CesiumGeospatial::LocalHorizontalCoordinateSystem _coordinateSystem{ glm::dmat4(1.0)};