Skip to content

Commit

Permalink
First cut of a working origin shift component.
Browse files Browse the repository at this point in the history
  • Loading branch information
kring committed Sep 12, 2023
1 parent ae15259 commit 05fcf04
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 69 deletions.
6 changes: 3 additions & 3 deletions Source/CesiumEditor/Private/CesiumEditorSubLevelMutex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ void CesiumEditorSubLevelMutex::OnMarkRenderStateDirty(
return;

if (!pLevelInstance->IsTemporarilyHiddenInEditor(true)) {
pSwitcher->SetTarget(pLevelInstance);
} else if (pSwitcher->GetTarget() == pLevelInstance) {
pSwitcher->SetTarget(nullptr);
pSwitcher->SetTargetSubLevel(pLevelInstance);
} else if (pSwitcher->GetTargetSubLevel() == pLevelInstance) {
pSwitcher->SetTargetSubLevel(nullptr);
}
}
22 changes: 11 additions & 11 deletions Source/CesiumRuntime/Private/CesiumGeoreference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ void ACesiumGeoreference::_showSubLevelLoadRadii() const {
}

for (const auto& pLevelWeak :
this->SubLevelSwitcher->GetRegisteredSubLevels()) {
this->SubLevelSwitcher->GetRegisteredSubLevelsWeak()) {
ALevelInstance* pLevel = pLevelWeak.Get();
if (!IsValid(pLevel))
continue;
Expand Down Expand Up @@ -402,9 +402,9 @@ void ACesiumGeoreference::Tick(float DeltaTime) {
_showSubLevelLoadRadii();
#endif

if (this->_shouldManageSubLevels()) {
_updateSublevelState();
}
// if (this->_shouldManageSubLevels()) {
// _updateSublevelState();
//}
}

void ACesiumGeoreference::Serialize(FArchive& Ar) {
Expand Down Expand Up @@ -599,7 +599,7 @@ void ACesiumGeoreference::_createSubLevelsFromWorldComposition() {
pLevelInstance->LoadLevelInstance();
}

this->SubLevelSwitcher->SetTarget(pActiveSubLevel);
this->SubLevelSwitcher->SetTargetSubLevel(pActiveSubLevel);

this->CesiumSubLevels_DEPRECATED.Empty();

Expand Down Expand Up @@ -648,10 +648,10 @@ void ACesiumGeoreference::UpdateGeoreference() {

// If we're in a sub-level, update its origin as well.
UCesiumSubLevelSwitcherComponent* pSwitcher = this->SubLevelSwitcher;
if (IsValid(pSwitcher) && pSwitcher->GetTarget() != nullptr) {
if (pSwitcher->GetTarget() == pSwitcher->GetCurrent() ||
pSwitcher->GetCurrent() == nullptr) {
ALevelInstance* pTarget = pSwitcher->GetTarget();
if (IsValid(pSwitcher) && pSwitcher->GetTargetSubLevel() != nullptr) {
if (pSwitcher->GetTargetSubLevel() == pSwitcher->GetCurrentSubLevel() ||
pSwitcher->GetCurrentSubLevel() == nullptr) {
ALevelInstance* pTarget = pSwitcher->GetTargetSubLevel();
UCesiumSubLevelComponent* pComponent =
pTarget->FindComponentByClass<UCesiumSubLevelComponent>();
if (IsValid(pComponent)) {
Expand Down Expand Up @@ -686,7 +686,7 @@ FName ACesiumGeoreference::DEFAULT_GEOREFERENCE_TAG =

bool ACesiumGeoreference::_updateSublevelState() {
const TArray<TWeakObjectPtr<ALevelInstance>>& sublevels =
this->SubLevelSwitcher->GetRegisteredSubLevels();
this->SubLevelSwitcher->GetRegisteredSubLevelsWeak();

if (sublevels.Num() == 0) {
// If we don't have any known sub-levels, bail quickly to save ourselves a
Expand Down Expand Up @@ -742,7 +742,7 @@ bool ACesiumGeoreference::_updateSublevelState() {
}
}

this->SubLevelSwitcher->SetTarget(pClosestActiveLevel);
this->SubLevelSwitcher->SetTargetSubLevel(pClosestActiveLevel);

return pClosestActiveLevel != nullptr;
}
Expand Down
4 changes: 2 additions & 2 deletions Source/CesiumRuntime/Private/CesiumGlobeAnchorComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ CesiumGeospatial::GlobeAnchor UCesiumGlobeAnchorComponent::
assert(pGeoreference != nullptr);

const CesiumGeospatial::LocalHorizontalCoordinateSystem& local =
pGeoreference->getCoordinateSystem();
pGeoreference->GetCoordinateSystem();

glm::dmat4 newModelToLocal =
VecMath::createMatrix4D(newRelativeTransform.ToMatrixWithScale());
Expand Down Expand Up @@ -662,7 +662,7 @@ void UCesiumGlobeAnchorComponent::_updateFromNativeGlobeAnchor(
ACesiumGeoreference* pGeoreference = this->ResolveGeoreference();
if (IsValid(pGeoreference)) {
glm::dmat4 anchorToLocal = nativeAnchor.getAnchorToLocalTransform(
pGeoreference->getCoordinateSystem());
pGeoreference->GetCoordinateSystem());

this->_setCurrentRelativeTransform(
FTransform(VecMath::createMatrix(anchorToLocal)));
Expand Down
103 changes: 103 additions & 0 deletions Source/CesiumRuntime/Private/CesiumOriginShiftComponent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2020-2023 CesiumGS, Inc. and Contributors

#include "CesiumOriginShiftComponent.h"
#include "CesiumGeoreference.h"
#include "CesiumGlobeAnchorComponent.h"
#include "CesiumSubLevelComponent.h"
#include "CesiumSubLevelSwitcherComponent.h"
#include "CesiumWgs84Ellipsoid.h"
#include "LevelInstance/LevelInstanceActor.h"

class ALevelInstance;

UCesiumOriginShiftComponent::UCesiumOriginShiftComponent() : Super() {
this->PrimaryComponentTick.bCanEverTick = true;
this->PrimaryComponentTick.TickGroup = ETickingGroup::TG_PrePhysics;
}

void UCesiumOriginShiftComponent::BeginPlay() {
Super::BeginPlay();

this->GlobeAnchor = nullptr;

AActor* Owner = this->GetOwner();
if (!Owner)
return;

this->GlobeAnchor =
Owner->FindComponentByClass<UCesiumGlobeAnchorComponent>();
if (!this->GlobeAnchor) {
// A globe anchor is missing and required, so add one.
this->GlobeAnchor =
Cast<UCesiumGlobeAnchorComponent>(Owner->AddComponentByClass(
UCesiumGlobeAnchorComponent::StaticClass(),
false,
FTransform::Identity,
false));
Owner->AddInstanceComponent(this->GlobeAnchor);
}
}

void UCesiumOriginShiftComponent::TickComponent(
float DeltaTime,
ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

if (!this->GlobeAnchor)
return;

ACesiumGeoreference* Georeference = this->GlobeAnchor->ResolveGeoreference();

if (!Georeference)
return;

UCesiumSubLevelSwitcherComponent* Switcher =
Georeference->GetSubLevelSwitcher();
if (!Switcher)
return;

const TArray<TWeakObjectPtr<ALevelInstance>>& Sublevels =
Switcher->GetRegisteredSubLevelsWeak();

if (Sublevels.Num() == 0) {
// If we don't have any known sub-levels, bail quickly to save ourselves a
// little work.
return;
}

FVector ActorEcef = this->GlobeAnchor->GetEarthCenteredEarthFixedPosition();

ALevelInstance* ClosestActiveLevel = nullptr;
double ClosestLevelDistance = std::numeric_limits<double>::max();

for (int32 i = 0; i < Sublevels.Num(); ++i) {
ALevelInstance* Current = Sublevels[i].Get();
if (!IsValid(Current))
continue;

UCesiumSubLevelComponent* SubLevelComponent =
Current->FindComponentByClass<UCesiumSubLevelComponent>();
if (!IsValid(SubLevelComponent))
continue;

if (!SubLevelComponent->GetEnabled())
continue;

FVector LevelEcef =
UCesiumWgs84Ellipsoid::LongitudeLatitudeHeightToEarthCenteredEarthFixed(
FVector(
SubLevelComponent->GetOriginLongitude(),
SubLevelComponent->GetOriginLatitude(),
SubLevelComponent->GetOriginHeight()));

double LevelDistance = FVector::Distance(LevelEcef, ActorEcef);
if (LevelDistance < SubLevelComponent->GetLoadRadius() &&
LevelDistance < ClosestLevelDistance) {
ClosestActiveLevel = Current;
ClosestLevelDistance = LevelDistance;
}
}

Switcher->SetTargetSubLevel(ClosestActiveLevel);
}
6 changes: 3 additions & 3 deletions Source/CesiumRuntime/Private/CesiumSubLevelComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ void UCesiumSubLevelComponent::UpdateGeoreferenceIfSubLevelIsActive() {
if (!pSwitcher)
return;

ALevelInstance* pCurrent = pSwitcher->GetCurrent();
ALevelInstance* pTarget = pSwitcher->GetTarget();
ALevelInstance* pCurrent = pSwitcher->GetCurrentSubLevel();
ALevelInstance* pTarget = pSwitcher->GetTargetSubLevel();

// This sub-level's origin is active if it is the current level or if it's the
// target level and there is no current level.
Expand Down Expand Up @@ -290,7 +290,7 @@ void UCesiumSubLevelComponent::OnComponentCreated() {
!this->GetWorld()->IsGameWorld()) {
ALevelInstance* pOwner = Cast<ALevelInstance>(this->GetOwner());
if (IsValid(pOwner) && !pOwner->IsTemporarilyHiddenInEditor(true)) {
pSwitcher->SetTarget(pOwner);
pSwitcher->SetTargetSubLevel(pOwner);
}
}
#endif
Expand Down
42 changes: 17 additions & 25 deletions Source/CesiumRuntime/Private/CesiumSubLevelSwitcherComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,29 @@ void UCesiumSubLevelSwitcherComponent::UnregisterSubLevel(
this->_doExtraChecksOnNextTick = true;
}

const TArray<TWeakObjectPtr<ALevelInstance>>&
TArray<ALevelInstance*>
UCesiumSubLevelSwitcherComponent::GetRegisteredSubLevels() const noexcept {
return this->_sublevels;
TArray<ALevelInstance*> result;
result.Reserve(this->_sublevels.Num());
for (const TWeakObjectPtr<ALevelInstance>& pWeak : this->_sublevels) {
ALevelInstance* p = pWeak.Get();
if (p)
result.Add(p);
}
return result;
}

ALevelInstance* UCesiumSubLevelSwitcherComponent::GetCurrent() const noexcept {
ALevelInstance*
UCesiumSubLevelSwitcherComponent::GetCurrentSubLevel() const noexcept {
return this->_pCurrent.Get();
}

ALevelInstance* UCesiumSubLevelSwitcherComponent::GetTarget() const noexcept {
ALevelInstance*
UCesiumSubLevelSwitcherComponent::GetTargetSubLevel() const noexcept {
return this->_pTarget.Get();
}

void UCesiumSubLevelSwitcherComponent::SetTarget(
void UCesiumSubLevelSwitcherComponent::SetTargetSubLevel(
ALevelInstance* pLevelInstance) noexcept {
if (this->_pTarget != pLevelInstance) {
if (pLevelInstance) {
Expand All @@ -93,24 +102,6 @@ void UCesiumSubLevelSwitcherComponent::SetTarget(
}
}

#if WITH_EDITOR

void UCesiumSubLevelSwitcherComponent::
NotifySubLevelIsTemporarilyHiddenInEditorChanged(
ALevelInstance* pLevelInstance,
bool bIsHidden) {
if (bIsHidden) {
// The previous target level has been hidden, so clear out the target.
if (this->_pTarget == pLevelInstance) {
this->SetTarget(nullptr);
}
} else {
this->SetTarget(pLevelInstance);
}
}

#endif

void UCesiumSubLevelSwitcherComponent::TickComponent(
float DeltaTime,
enum ELevelTick TickType,
Expand All @@ -121,7 +112,7 @@ void UCesiumSubLevelSwitcherComponent::TickComponent(
if (this->_pTarget != nullptr &&
this->_sublevels.Find(this->_pTarget) == INDEX_NONE) {
// Target level is no longer registered, so the new target is "none".
this->SetTarget(nullptr);
this->SetTargetSubLevel(nullptr);
}

// In game, make sure that any sub-levels that aren't pCurrent or pTarget
Expand Down Expand Up @@ -303,7 +294,8 @@ void UCesiumSubLevelSwitcherComponent::_updateSubLevelStateGame() {

// Double-check that we're not actively trying to unload this level
// already. If we are, wait longer.
if (IsValid(pStreaming) && pStreaming->ShouldBeLoaded()) {
if ((IsValid(pStreaming) && pStreaming->ShouldBeLoaded()) ||
this->_pTarget.Get()->GetWorldAsset().IsNull()) {
this->_pCurrent = this->_pTarget;
} else {
this->_isTransitioningSubLevels = true;
Expand Down
26 changes: 22 additions & 4 deletions Source/CesiumRuntime/Public/CesiumGeoreference.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor {
meta = (AllowPrivateAccess))
APlayerCameraManager* SubLevelCamera = nullptr;

/**
* The component that allows switching between the sub-levels registered with
* this georeference.
*/
UPROPERTY(
Instanced,
Category = "Cesium|Sub-levels",
BlueprintReadOnly,
BlueprintGetter = GetSubLevelSwitcher,
meta = (AllowPrivateAccess))
UCesiumSubLevelSwitcherComponent* SubLevelSwitcher;

#if WITH_EDITORONLY_DATA
/**
* Whether to visualize the level loading radii in the editor. Helpful for
Expand Down Expand Up @@ -330,6 +342,15 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor {
UFUNCTION(BlueprintSetter)
void SetSubLevelCamera(APlayerCameraManager* NewValue);

/**
* Gets the component that allows switching between different sub-levels
* registered with this georeference.
*/
UFUNCTION(BlueprintGetter)
UCesiumSubLevelSwitcherComponent* GetSubLevelSwitcher() {
return this->SubLevelSwitcher;
}

#if WITH_EDITOR
/**
* Gets whether to visualize the level loading radii in the editor. Helpful
Expand Down Expand Up @@ -721,7 +742,7 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor {
ACesiumGeoreference();

const CesiumGeospatial::LocalHorizontalCoordinateSystem&
getCoordinateSystem() const noexcept {
GetCoordinateSystem() const noexcept {
return this->_coordinateSystem;
}

Expand All @@ -741,9 +762,6 @@ class CESIUMRUNTIME_API ACesiumGeoreference : public AActor {
CesiumGeospatial::LocalHorizontalCoordinateSystem _coordinateSystem{
glm::dmat4(1.0)};

UPROPERTY()
UCesiumSubLevelSwitcherComponent* SubLevelSwitcher;

/**
* @brief Updates the load state of sub-levels.
*
Expand Down
30 changes: 30 additions & 0 deletions Source/CesiumRuntime/Public/CesiumOriginShiftComponent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2020-2023 CesiumGS, Inc. and Contributors

#pragma once

#include "Components/ActorComponent.h"
#include "CoreMinimal.h"
#include "CesiumOriginShiftComponent.generated.h"

class UCesiumGlobeAnchorComponent;

UCLASS(ClassGroup = "Cesium", Meta = (BlueprintSpawnableComponent))
class CESIUMRUNTIME_API UCesiumOriginShiftComponent : public UActorComponent {
GENERATED_BODY()

public:
UCesiumOriginShiftComponent();

protected:
virtual void BeginPlay() override;
virtual void TickComponent(
float DeltaTime,
enum ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;

private:
// The globe anchor attached to the same Actor as this component. Don't
// save/load or copy this. It is set in BeginPlay.
UPROPERTY(Transient, DuplicateTransient, TextExportTransient)
UCesiumGlobeAnchorComponent* GlobeAnchor;
};
Loading

0 comments on commit 05fcf04

Please sign in to comment.