diff --git a/Source/CesiumRuntime/Private/CesiumFlyToComponent.cpp b/Source/CesiumRuntime/Private/CesiumFlyToComponent.cpp index cd8997afd..e09993786 100644 --- a/Source/CesiumRuntime/Private/CesiumFlyToComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumFlyToComponent.cpp @@ -170,6 +170,10 @@ void UCesiumFlyToComponent::InterruptFlight() { OnFlightInterrupted.Broadcast(); } +bool UCesiumFlyToComponent::IsFlightInProgress() { + return this->_flightInProgress; +} + void UCesiumFlyToComponent::TickComponent( float DeltaTime, ELevelTick TickType, diff --git a/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.cpp b/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.cpp index efdc27401..c12ace56f 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.cpp +++ b/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.cpp @@ -15,35 +15,15 @@ namespace Cesium { -struct LoadTestContext { - FString testName; - std::vector testPasses; - - SceneGenerationContext creationContext; - SceneGenerationContext playContext; - - float cameraFieldOfView = 90.0f; - - ReportCallback reportStep; - - void reset() { - testName.Reset(); - testPasses.clear(); - creationContext = playContext = SceneGenerationContext(); - reportStep = nullptr; - } -}; +inline void LoadTestContext::reset() { + testName.Reset(); + testPasses.clear(); + creationContext = playContext = SceneGenerationContext(); + reportStep = nullptr; +} LoadTestContext gLoadTestContext; -DEFINE_LATENT_AUTOMATION_COMMAND_THREE_PARAMETER( - TimeLoadingCommand, - FString, - loggingName, - SceneGenerationContext&, - playContext, - TestPass&, - pass); bool TimeLoadingCommand::Update() { if (!pass.testInProgress) { @@ -106,10 +86,6 @@ bool TimeLoadingCommand::Update() { return false; } -DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER( - LoadTestScreenshotCommand, - FString, - screenshotName); bool LoadTestScreenshotCommand::Update() { UE_LOG( LogCesium, @@ -139,10 +115,6 @@ void defaultReportStep(const std::vector& testPasses) { UE_LOG(LogCesium, Display, TEXT("%s"), *reportStr); } -DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER( - TestCleanupCommand, - LoadTestContext&, - context); bool TestCleanupCommand::Update() { // Tag the fastest pass if (context.testPasses.size() > 0) { @@ -168,12 +140,6 @@ bool TestCleanupCommand::Update() { return true; } -DEFINE_LATENT_AUTOMATION_COMMAND_TWO_PARAMETER( - InitForPlayWhenReady, - SceneGenerationContext&, - creationContext, - SceneGenerationContext&, - playContext); bool InitForPlayWhenReady::Update() { if (!GEditor || !GEditor->IsPlayingSessionInEditor()) return false; diff --git a/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.h b/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.h index ee5188b0d..48d79cb2c 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.h +++ b/Source/CesiumRuntime/Private/Tests/CesiumLoadTestCore.h @@ -8,28 +8,26 @@ #include #include "CesiumSceneGeneration.h" +#include "CesiumTestPass.h" +#include "Tests/AutomationCommon.h" namespace Cesium { -struct TestPass { - typedef std::variant TestingParameter; - typedef std::function - PassCallback; +typedef std::function&)> ReportCallback; - FString name; - PassCallback setupStep; - PassCallback verifyStep; - TestingParameter optionalParameter; +struct LoadTestContext { + FString testName; + std::vector testPasses; - bool testInProgress = false; - double startMark = 0; - double endMark = 0; - double elapsedTime = 0; + SceneGenerationContext creationContext; + SceneGenerationContext playContext; - bool isFastest = false; -}; + float cameraFieldOfView = 90.0f; -typedef std::function&)> ReportCallback; + ReportCallback reportStep; + + void reset(); +}; bool RunLoadTest( const FString& testName, @@ -39,6 +37,32 @@ bool RunLoadTest( int viewportHeight, ReportCallback optionalReportStep = nullptr); +DEFINE_LATENT_AUTOMATION_COMMAND_THREE_PARAMETER( + TimeLoadingCommand, + FString, + loggingName, + SceneGenerationContext&, + playContext, + TestPass&, + pass); + +DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER( + LoadTestScreenshotCommand, + FString, + screenshotName); + +DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER( + TestCleanupCommand, + LoadTestContext&, + context); + +DEFINE_LATENT_AUTOMATION_COMMAND_TWO_PARAMETER( + InitForPlayWhenReady, + SceneGenerationContext&, + creationContext, + SceneGenerationContext&, + playContext); + }; // namespace Cesium #endif diff --git a/Source/CesiumRuntime/Private/Tests/CesiumSceneGeneration.cpp b/Source/CesiumRuntime/Private/Tests/CesiumSceneGeneration.cpp index 05a24035b..42302ffd3 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumSceneGeneration.cpp +++ b/Source/CesiumRuntime/Private/Tests/CesiumSceneGeneration.cpp @@ -10,7 +10,10 @@ #include "LevelEditorViewport.h" #include "Cesium3DTileset.h" +#include "CesiumAsync/ICacheDatabase.h" #include "CesiumGeoreference.h" +#include "CesiumLoadTestCore.h" +#include "CesiumRuntime.h" #include "CesiumSunSky.h" #include "GlobeAwareDefaultPawn.h" diff --git a/Source/CesiumRuntime/Private/Tests/CesiumTestPass.h b/Source/CesiumRuntime/Private/Tests/CesiumTestPass.h new file mode 100644 index 000000000..2f430c33d --- /dev/null +++ b/Source/CesiumRuntime/Private/Tests/CesiumTestPass.h @@ -0,0 +1,33 @@ +#pragma once + +#if WITH_EDITOR + +#include +#include + +#include "CesiumSceneGeneration.h" +#include "Tests/AutomationCommon.h" + +namespace Cesium { + +struct TestPass { + typedef std::variant TestingParameter; + typedef std::function + PassCallback; + + FString name; + PassCallback setupStep; + PassCallback verifyStep; + TestingParameter optionalParameter; + + bool testInProgress = false; + double startMark = 0; + double endMark = 0; + double elapsedTime = 0; + + bool isFastest = false; +}; + +} // namespace Cesium + +#endif diff --git a/Source/CesiumRuntime/Private/Tests/Google3dTilesLoadTest.cpp b/Source/CesiumRuntime/Private/Tests/Google3dTilesLoadTest.cpp index 94eea489f..85fad38f8 100644 --- a/Source/CesiumRuntime/Private/Tests/Google3dTilesLoadTest.cpp +++ b/Source/CesiumRuntime/Private/Tests/Google3dTilesLoadTest.cpp @@ -7,6 +7,8 @@ #include "Engine/World.h" #include "Misc/AutomationTest.h" +#include "GoogleTilesTestSetup.h" + #include "Cesium3DTileset.h" #include "CesiumAsync/ICacheDatabase.h" #include "CesiumRuntime.h" @@ -62,134 +64,14 @@ IMPLEMENT_SIMPLE_AUTOMATION_TEST( #define TEST_SCREEN_WIDTH 1280 #define TEST_SCREEN_HEIGHT 720 -void googleSetupRefreshTilesets( - SceneGenerationContext& context, - TestPass::TestingParameter parameter) { - context.refreshTilesets(); -} - -void googleSetupClearCache( - SceneGenerationContext& context, - TestPass::TestingParameter parameter) { - std::shared_ptr pCacheDatabase = - getCacheDatabase(); - pCacheDatabase->clearAll(); -} - -void setupForPompidou(SceneGenerationContext& context) { - context.setCommonProperties( - FVector(2.352200, 48.860600, 200), - FVector(0, 0, 0), - FRotator(-20.0, -90.0, 0.0), - 60.0f); - - context.sunSky->TimeZone = 2.0f; - context.sunSky->UpdateSun(); - - ACesium3DTileset* tileset = context.world->SpawnActor(); - tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); - tileset->SetIonAssetID(2275207); - tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); - tileset->SetActorLabel(TEXT("Center Pompidou, Paris, France")); - context.tilesets.push_back(tileset); -} - -void setupForChrysler(SceneGenerationContext& context) { - context.setCommonProperties( - FVector(-73.9752624659, 40.74697185903, 307.38), - FVector(0, 0, 0), - FRotator(-15.0, -90.0, 0.0), - 60.0f); - - context.sunSky->TimeZone = -4.0f; - context.sunSky->UpdateSun(); - - ACesium3DTileset* tileset = context.world->SpawnActor(); - tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); - tileset->SetIonAssetID(2275207); - tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); - tileset->SetActorLabel(TEXT("Chrysler Building, NYC")); - context.tilesets.push_back(tileset); -} - -void setupForGuggenheim(SceneGenerationContext& context) { - context.setCommonProperties( - FVector(-2.937, 43.2685, 150), - FVector(0, 0, 0), - FRotator(-15.0, 0.0, 0.0), - 60.0f); - - context.sunSky->TimeZone = 2.0f; - context.sunSky->UpdateSun(); - - ACesium3DTileset* tileset = context.world->SpawnActor(); - tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); - tileset->SetIonAssetID(2275207); - tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); - tileset->SetActorLabel(TEXT("Guggenheim Museum, Bilbao, Spain")); - context.tilesets.push_back(tileset); -} - -void setupForDeathValley(SceneGenerationContext& context) { - context.setCommonProperties( - FVector(-116.812278, 36.42, 300), - FVector(0, 0, 0), - FRotator(0, 0.0, 0.0), - 60.0f); - - context.sunSky->TimeZone = -7.0f; - context.sunSky->UpdateSun(); - - ACesium3DTileset* tileset = context.world->SpawnActor(); - tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); - tileset->SetIonAssetID(2275207); - tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); - tileset->SetActorLabel( - TEXT("Zabriskie Point, Death Valley National Park, California")); - context.tilesets.push_back(tileset); -} - -void setupForTokyo(SceneGenerationContext& context) { - context.setCommonProperties( - FVector(139.7563178458, 35.652798383944, 525.62), - FVector(0, 0, 0), - FRotator(-15, -150, 0.0), - 60.0f); - - context.sunSky->TimeZone = 9.0f; - context.sunSky->UpdateSun(); - - ACesium3DTileset* tileset = context.world->SpawnActor(); - tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); - tileset->SetIonAssetID(2275207); - tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); - tileset->SetActorLabel(TEXT("Tokyo Tower, Tokyo, Japan")); - context.tilesets.push_back(tileset); -} - -void setupForGoogleplex(SceneGenerationContext& context) { - context.setCommonProperties( - FVector(-122.083969, 37.424492, 142.859116), - FVector(0, 0, 0), - FRotator(-25, 95, 0), - 90.0f); - - ACesium3DTileset* tileset = context.world->SpawnActor(); - tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); - tileset->SetIonAssetID(2275207); - tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); - tileset->SetActorLabel(TEXT("Google Photorealistic 3D Tiles")); - - context.tilesets.push_back(tileset); -} - bool FGoogleTilesPompidou::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back(TestPass{"Cold Cache", googleSetupClearCache, nullptr}); + testPasses.push_back( + TestPass{"Cold Cache", GoogleTilesTestSetup::setupClearCache, nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForPompidou, + GoogleTilesTestSetup::setupForPompidou, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -197,11 +79,12 @@ bool FGoogleTilesPompidou::RunTest(const FString& Parameters) { bool FGoogleTilesChrysler::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back(TestPass{"Cold Cache", googleSetupClearCache, nullptr}); + testPasses.push_back( + TestPass{"Cold Cache", GoogleTilesTestSetup::setupClearCache, nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForChrysler, + GoogleTilesTestSetup::setupForChrysler, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -209,12 +92,14 @@ bool FGoogleTilesChrysler::RunTest(const FString& Parameters) { bool FGoogleTilesChryslerWarm::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back( - TestPass{"Warm Cache", googleSetupRefreshTilesets, nullptr}); + testPasses.push_back(TestPass{ + "Warm Cache", + GoogleTilesTestSetup::setupRefreshTilesets, + nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForChrysler, + GoogleTilesTestSetup::setupForChrysler, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -222,11 +107,12 @@ bool FGoogleTilesChryslerWarm::RunTest(const FString& Parameters) { bool FGoogleTilesGuggenheim::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back(TestPass{"Cold Cache", googleSetupClearCache, nullptr}); + testPasses.push_back( + TestPass{"Cold Cache", GoogleTilesTestSetup::setupClearCache, nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForGuggenheim, + GoogleTilesTestSetup::setupForGuggenheim, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -234,11 +120,12 @@ bool FGoogleTilesGuggenheim::RunTest(const FString& Parameters) { bool FGoogleTilesDeathValley::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back(TestPass{"Cold Cache", googleSetupClearCache, nullptr}); + testPasses.push_back( + TestPass{"Cold Cache", GoogleTilesTestSetup::setupClearCache, nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForDeathValley, + GoogleTilesTestSetup::setupForDeathValley, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -246,12 +133,14 @@ bool FGoogleTilesDeathValley::RunTest(const FString& Parameters) { bool FGoogleTilesDeathValleyWarm::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back( - TestPass{"Warm Cache", googleSetupRefreshTilesets, nullptr}); + testPasses.push_back(TestPass{ + "Warm Cache", + GoogleTilesTestSetup::setupRefreshTilesets, + nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForDeathValley, + GoogleTilesTestSetup::setupForDeathValley, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -259,11 +148,12 @@ bool FGoogleTilesDeathValleyWarm::RunTest(const FString& Parameters) { bool FGoogleTilesTokyo::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back(TestPass{"Cold Cache", googleSetupClearCache, nullptr}); + testPasses.push_back( + TestPass{"Cold Cache", GoogleTilesTestSetup::setupClearCache, nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForTokyo, + GoogleTilesTestSetup::setupForTokyo, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -271,11 +161,12 @@ bool FGoogleTilesTokyo::RunTest(const FString& Parameters) { bool FGoogleTilesGoogleplex::RunTest(const FString& Parameters) { std::vector testPasses; - testPasses.push_back(TestPass{"Cold Cache", googleSetupClearCache, nullptr}); + testPasses.push_back( + TestPass{"Cold Cache", GoogleTilesTestSetup::setupClearCache, nullptr}); return RunLoadTest( GetBeautifiedTestName(), - setupForGoogleplex, + GoogleTilesTestSetup::setupForGoogleplex, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); @@ -296,7 +187,8 @@ bool FGoogleTilesMaxTileLoads::RunTest(const FString& Parameters) { }; std::vector testPasses; - testPasses.push_back(TestPass{"Default", googleSetupClearCache, NULL}); + testPasses.push_back( + TestPass{"Default", GoogleTilesTestSetup::setupClearCache, NULL}); testPasses.push_back(TestPass{"12", setupPass, NULL, 12}); testPasses.push_back(TestPass{"16", setupPass, NULL, 16}); testPasses.push_back(TestPass{"20", setupPass, NULL, 20}); @@ -305,7 +197,7 @@ bool FGoogleTilesMaxTileLoads::RunTest(const FString& Parameters) { return RunLoadTest( GetBeautifiedTestName(), - setupForChrysler, + GoogleTilesTestSetup::setupForChrysler, testPasses, TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT); diff --git a/Source/CesiumRuntime/Private/Tests/GoogleTilesTestSetup.cpp b/Source/CesiumRuntime/Private/Tests/GoogleTilesTestSetup.cpp new file mode 100644 index 000000000..baa1542a5 --- /dev/null +++ b/Source/CesiumRuntime/Private/Tests/GoogleTilesTestSetup.cpp @@ -0,0 +1,109 @@ +#include "GoogleTilesTestSetup.h" + +#include "Cesium3DTileset.h" +#include "CesiumAsync/ICacheDatabase.h" +#include "CesiumLoadTestCore.h" +#include "CesiumRuntime.h" +#include "CesiumSunSky.h" + +namespace Cesium { + +inline void GoogleTilesTestSetup::setupRefreshTilesets( + SceneGenerationContext& context, + TestPass::TestingParameter parameter) { + context.refreshTilesets(); +} + +inline void GoogleTilesTestSetup::setupClearCache( + SceneGenerationContext& context, + TestPass::TestingParameter parameter) { + std::shared_ptr pCacheDatabase = + getCacheDatabase(); + pCacheDatabase->clearAll(); +} + +inline void GoogleTilesTestSetup::setupForLocation( + SceneGenerationContext& context, + const FVector& location, + const FRotator& rotation, + const FString& name) { + context.setCommonProperties(location, FVector::ZeroVector, rotation, 60.0f); + + ACesium3DTileset* tileset = context.world->SpawnActor(); + tileset->SetTilesetSource(ETilesetSource::FromCesiumIon); + tileset->SetIonAssetID(2275207); + tileset->SetIonAccessToken(SceneGenerationContext::testIonToken); + tileset->SetActorLabel(name); + context.tilesets.push_back(tileset); +} + +inline void +GoogleTilesTestSetup::setupForPompidou(SceneGenerationContext& context) { + setupForLocation( + context, + FVector(2.352200, 48.860600, 200), + FRotator(-20.0, -90.0, 0.0), + TEXT("Center Pompidou, Paris, France")); + + context.sunSky->TimeZone = 2.0f; + context.sunSky->UpdateSun(); +} + +inline void +GoogleTilesTestSetup::setupForChrysler(SceneGenerationContext& context) { + setupForLocation( + context, + FVector(-73.9752624659, 40.74697185903, 307.38), + FRotator(-15.0, -90.0, 0.0), + TEXT("Chrysler Building, NYC")); + + context.sunSky->TimeZone = -4.0f; + context.sunSky->UpdateSun(); +} + +inline void +GoogleTilesTestSetup::setupForGuggenheim(SceneGenerationContext& context) { + setupForLocation( + context, + FVector(-2.937, 43.2685, 150), + FRotator(-15.0, 0.0, 0.0), + TEXT("Guggenheim Museum, Bilbao, Spain")); + + context.sunSky->TimeZone = 2.0f; + context.sunSky->UpdateSun(); +} + +inline void +GoogleTilesTestSetup::setupForDeathValley(SceneGenerationContext& context) { + setupForLocation( + context, + FVector(-116.812278, 36.42, 300), + FRotator(0, 0.0, 0.0), + TEXT("Zabriskie Point, Death Valley National Park, California")); + + context.sunSky->TimeZone = -7.0f; + context.sunSky->UpdateSun(); +} + +inline void +GoogleTilesTestSetup::setupForTokyo(SceneGenerationContext& context) { + setupForLocation( + context, + FVector(139.7563178458, 35.652798383944, 525.62), + FRotator(-15, -150, 0.0), + TEXT("Tokyo Tower, Tokyo, Japan")); + + context.sunSky->TimeZone = 9.0f; + context.sunSky->UpdateSun(); +} + +inline void +GoogleTilesTestSetup::setupForGoogleplex(SceneGenerationContext& context) { + setupForLocation( + context, + FVector(-122.083969, 37.424492, 142.859116), + FRotator(-25, 95, 0), + TEXT("Google Photorealistic 3D Tiles")); +} + +} // namespace Cesium diff --git a/Source/CesiumRuntime/Private/Tests/GoogleTilesTestSetup.h b/Source/CesiumRuntime/Private/Tests/GoogleTilesTestSetup.h new file mode 100644 index 000000000..16edadaf1 --- /dev/null +++ b/Source/CesiumRuntime/Private/Tests/GoogleTilesTestSetup.h @@ -0,0 +1,35 @@ +#pragma once + +#if WITH_EDITOR + +#include "CesiumSceneGeneration.h" +#include "CesiumTestPass.h" + +namespace Cesium { + +struct GoogleTilesTestSetup { + static void setupRefreshTilesets( + SceneGenerationContext& context, + TestPass::TestingParameter parameter); + + static void setupClearCache( + SceneGenerationContext& context, + TestPass::TestingParameter parameter); + + static void setupForLocation( + SceneGenerationContext& context, + const FVector& location, + const FRotator& rotation, + const FString& name); + + static void setupForPompidou(SceneGenerationContext& context); + static void setupForChrysler(SceneGenerationContext& context); + static void setupForGuggenheim(SceneGenerationContext& context); + static void setupForDeathValley(SceneGenerationContext& context); + static void setupForTokyo(SceneGenerationContext& context); + static void setupForGoogleplex(SceneGenerationContext& context); +}; + +} // namespace Cesium + +#endif diff --git a/Source/CesiumRuntime/Private/Tests/TestRegionPolygons.cpp b/Source/CesiumRuntime/Private/Tests/TestRegionPolygons.cpp new file mode 100644 index 000000000..458bc93c0 --- /dev/null +++ b/Source/CesiumRuntime/Private/Tests/TestRegionPolygons.cpp @@ -0,0 +1,192 @@ +#include "TestRegionPolygons.h" + +#include + +namespace Cesium { +static const TestPolygon testRegionPolygonsData[] = { + {FVector2D(-74.2013321117691, 40.9774450853578), + FVector2D(-74.4593744591054, 40.514167617152), + FVector2D(-72.9155255739658, 40.7042737041433), + FVector2D(-73.85290089588, 40.9326611125325), + FVector2D(-74.2013321117691, 40.9774450853578)}, + {FVector2D(-70.8665457211077, 42.5869988084598), + FVector2D(-71.3661722404885, 42.4639488342876), + FVector2D(-71.2972087427719, 42.1467522915001), + FVector2D(-70.7729743178252, 42.2335714316977), + FVector2D(-70.8665457211077, 42.5869988084598)}, + {FVector2D(-75.0239947410133, 40.1395284511288), + FVector2D(-75.4196355358948, 40.0148058322418), + FVector2D(-75.2636118623868, 39.7886799431864), + FVector2D(-74.7858557650542, 39.9438636936503), + FVector2D(-75.0239947410133, 40.1395284511288)}, + {FVector2D(-76.7463533262082, 39.4825406033305), + FVector2D(-77.4340311059877, 38.8258770447382), + FVector2D(-76.9547073596801, 38.6332198167468), + FVector2D(-76.2326804229044, 39.3697178750327), + FVector2D(-76.7463533262082, 39.4825406033305)}, + {FVector2D(-87.7880477582706, 42.484868555962), + FVector2D(-88.5878253665254, 42.3173994498162), + FVector2D(-88.2041661838266, 41.2937330828566), + FVector2D(-87.2835529091586, 41.5464660939422), + FVector2D(-87.7880477582706, 42.484868555962)}, + {FVector2D(-117.797555097187, 33.5210842049415), + FVector2D(-116.732710054453, 34.1503747429439), + FVector2D(-118.101396808054, 34.3250274422573), + FVector2D(-119.005372293813, 34.0462414684101), + FVector2D(-117.797555097187, 33.5210842049415)}, + {FVector2D(-121.952555819749, 37.0551315779953), + FVector2D(-121.472262225148, 37.2762707697842), + FVector2D(-122.308508157973, 38.2801293998287), + FVector2D(-122.735942423996, 37.8231990412902), + FVector2D(-121.952555819749, 37.0551315779953)}, + {FVector2D(-123.344029747329, 49.3851693056083), + FVector2D(-123.302612411589, 48.8580301457693), + FVector2D(-122.05501553595, 48.8358263385625), + FVector2D(-121.933325112706, 49.2715130224448), + FVector2D(-123.344029747329, 49.3851693056083)}, + {FVector2D(-98.894461647111, 19.1607853097298), + FVector2D(-98.7686431463364, 19.6183748878263), + FVector2D(-99.3048055915005, 19.6853872937311), + FVector2D(-99.3991868765643, 19.3265084381959), + FVector2D(-98.894461647111, 19.1607853097298)}, + {FVector2D(140.054350788689, 35.0230502784051), + FVector2D(140.412218892413, 36.3913714622335), + FVector2D(139.256616929582, 36.4982427020207), + FVector2D(139.10640870208, 34.9240606249587), + FVector2D(140.054350788689, 35.0230502784051)}, + {FVector2D(135.055269955952, 34.1165959544619), + FVector2D(136.010060967071, 34.3342346904423), + FVector2D(135.827593998297, 35.1609921898404), + FVector2D(134.951100611567, 34.7581621821003), + FVector2D(135.055269955952, 34.1165959544619)}, + {FVector2D(126.506482128111, 37.309652936223), + FVector2D(127.276578372058, 37.3152753352917), + FVector2D(127.276625945403, 37.7169510199583), + FVector2D(126.456565879908, 37.6708092887235), + FVector2D(126.506482128111, 37.309652936223)}, + {FVector2D(121.134001967184, 31.5497391098806), + FVector2D(121.162908585755, 30.9008622819707), + FVector2D(121.973194206992, 30.996871119183), + FVector2D(121.703379279597, 31.5459147489145), + FVector2D(121.134001967184, 31.5497391098806)}, + {FVector2D(113.118683475979, 21.9538081632891), + FVector2D(113.116571761854, 21.9536183257244), + FVector2D(114.51719761199, 22.1592194597545), + FVector2D(114.412643287974, 23.2156098976288), + FVector2D(112.968966605958, 23.1794019008474), + FVector2D(113.118683475979, 21.9538081632891)}, + {FVector2D(119.602455828861, 23.3701241133722), + FVector2D(120.43065363132, 22.7299422907066), + FVector2D(121.979122588007, 24.9890484436014), + FVector2D(121.331012296727, 25.3178637634457), + FVector2D(119.602455828861, 23.3701241133722)}, + {FVector2D(116.388332170902, 38.6463257232499), + FVector2D(118.085699455998, 38.898921209556), + FVector2D(117.787877280437, 40.1604047317278), + FVector2D(115.944808581142, 40.0167139637757), + FVector2D(116.388332170902, 38.6463257232499)}, + {FVector2D(120.760414545729, 14.3748010156788), + FVector2D(121.258394771143, 14.2501216390828), + FVector2D(121.290054862448, 14.7534041084167), + FVector2D(120.738158949159, 14.7593332219211), + FVector2D(120.760414545729, 14.3748010156788)}, + {FVector2D(103.50156107247, 0.998061113465564), + FVector2D(104.715513672489, 0.982204662790223), + FVector2D(104.334518818725, 1.70398117696512), + FVector2D(103.258944549305, 1.4844867069418), + FVector2D(103.50156107247, 0.998061113465564)}, + {FVector2D(105.881719721888, -5.74570400497445), + FVector2D(105.833559417072, -6.21278484163883), + FVector2D(108.186160253085, -6.47215807929743), + FVector2D(108.027660861491, -5.93654743166617), + FVector2D(105.881719721888, -5.74570400497445)}, + {FVector2D(150.583157022031, -34.0498630944677), + FVector2D(151.280108788925, -34.1723736264387), + FVector2D(151.430931749967, -33.6913578323042), + FVector2D(150.68777700301, -33.5004609703255), + FVector2D(150.583157022031, -34.0498630944677)}, + {FVector2D(100.362043393093, 13.5146830907152), + FVector2D(100.804723956777, 13.4902538260098), + FVector2D(100.857533774329, 14.0291484359391), + FVector2D(100.296514387822, 14.0180095766592), + FVector2D(100.362043393093, 13.5146830907152)}, + {FVector2D(72.8139207040816, 18.8644328953372), + FVector2D(73.0797035981117, 18.9090108585454), + FVector2D(73.0550830148766, 19.2511180020347), + FVector2D(72.765539257819, 19.2056123110889), + FVector2D(72.8139207040816, 18.8644328953372)}, + {FVector2D(76.9327816012394, 28.3841052539538), + FVector2D(77.4771720538251, 28.4833789366456), + FVector2D(77.3482561523984, 28.8846883488663), + FVector2D(76.8582384578204, 28.7963756494536), + FVector2D(76.9327816012394, 28.3841052539538)}, + {FVector2D(54.9429835012101, 25.0178517226697), + FVector2D(55.0946994816812, 24.8756220574815), + FVector2D(55.602636800682, 25.3172895563037), + FVector2D(55.3945349608567, 25.4562123460321), + FVector2D(54.9429835012101, 25.0178517226697)}, + {FVector2D(-3.61878369798117, 40.2775903261193), + FVector2D(-3.4906994656486, 40.4737663140241), + FVector2D(-3.72686800427542, 40.601926645219), + FVector2D(-3.89898175894152, 40.3290711912317), + FVector2D(-3.61878369798117, 40.2775903261193)}, + {FVector2D(-9.19296732462638, 38.3938592975828), + FVector2D(-8.75078735276178, 38.5702884330086), + FVector2D(-8.92050164224059, 38.9449362396636), + FVector2D(-9.5272031704166, 38.7658866470946), + FVector2D(-9.19296732462638, 38.3938592975828)}, + {FVector2D(1.81826634445193, 48.6429184198264), + FVector2D(2.57743142898819, 48.5161116317191), + FVector2D(2.81852244248245, 48.9958850870085), + FVector2D(2.08220061664221, 49.1112351713166), + FVector2D(1.81826634445193, 48.6429184198264)}, + {FVector2D(12.046678722878, 41.8734309143794), + FVector2D(12.538572569152, 41.5584390046116), + FVector2D(12.902473689969, 41.8844741109742), + FVector2D(12.3604328937937, 42.1775684704485), + FVector2D(12.046678722878, 41.8734309143794)}, + {FVector2D(13.0369523148704, 52.3264792264681), + FVector2D(13.7857078301483, 52.2432874392554), + FVector2D(13.7245722259762, 52.5706652767158), + FVector2D(13.0855894510726, 52.6398386596651), + FVector2D(13.0369523148704, 52.3264792264681)}, + {FVector2D(-0.540173561477041, 51.3275558776523), + FVector2D(0.366937281698374, 51.2972794865316), + FVector2D(0.378630660590049, 51.6312453736339), + FVector2D(-0.565434346898922, 51.6941551135231), + FVector2D(-0.540173561477041, 51.3275558776523)}, + {FVector2D(-3.44162716057316, 55.9042055474235), + FVector2D(-2.86557475273948, 55.8204519638228), + FVector2D(-2.76434520027445, 55.9879349630359), + FVector2D(-3.39396844082001, 56.0516294637465), + FVector2D(-3.44162716057316, 55.9042055474235)}, + {FVector2D(-6.45226364658212, 53.233148089773), + FVector2D(-5.94733626257021, 53.2160280458379), + FVector2D(-5.99718303046307, 53.4420617215498), + FVector2D(-6.53307425159679, 53.4371162576022), + FVector2D(-6.45226364658212, 53.233148089773)}}; + +const TestPolygon* TestRegionPolygons::polygons = testRegionPolygonsData; + +FVector TestPolygon::GetRandomPoint() const { + // For testing we don't need to actually generate a random point within the + // polygon - just use the polygon's bounding box. + double minX = std::numeric_limits::max(); + double minY = std::numeric_limits::max(); + double maxX = std::numeric_limits::min(); + double maxY = std::numeric_limits::min(); + + for (const FVector2D& point : this->points) { + minX = std::min(point.X, minX); + minY = std::min(point.Y, minY); + maxX = std::max(point.X, maxX); + maxY = std::max(point.Y, maxY); + } + + return FVector( + FMath::RandRange(minX, maxX), + FMath::RandRange(minY, maxY), + 0.0f); +} + +} // namespace Cesium diff --git a/Source/CesiumRuntime/Private/Tests/TestRegionPolygons.h b/Source/CesiumRuntime/Private/Tests/TestRegionPolygons.h new file mode 100644 index 000000000..7d5faa5eb --- /dev/null +++ b/Source/CesiumRuntime/Private/Tests/TestRegionPolygons.h @@ -0,0 +1,33 @@ +#pragma once + +#if WITH_EDITOR + +#include "VectorTypes.h" +#include +#include + +namespace Cesium { +struct TestPolygon { + TestPolygon(std::initializer_list points) : points(points) {} + + /** + * Returns a random point within this polygon to test with. + */ + FVector GetRandomPoint() const; + +private: + std::vector points; +}; + +// An array of test polygons delineating populated, high-interest areas to test +// with. +constexpr static int TEST_REGION_POLYGONS_COUNT = 32; + +class TestRegionPolygons { +public: + static const TestPolygon* polygons; +}; + +} // namespace Cesium + +#endif diff --git a/Source/CesiumRuntime/Private/Tests/TileLoadingSoakTest.cpp b/Source/CesiumRuntime/Private/Tests/TileLoadingSoakTest.cpp new file mode 100644 index 000000000..ee4faedf9 --- /dev/null +++ b/Source/CesiumRuntime/Private/Tests/TileLoadingSoakTest.cpp @@ -0,0 +1,275 @@ +// Copyright 2020-2024 CesiumGS, Inc. and Contributors + +#if WITH_EDITOR + +#include +#include +#include +#include + +#include + +#include "Containers/UnrealString.h" +#include "GenericPlatform/GenericPlatformFile.h" +#include "GenericPlatform/GenericPlatformMemory.h" +#include "GenericPlatform/GenericPlatformProcess.h" +#include "HAL/PlatformFileManager.h" +#include "Math/UnrealMathUtility.h" +#include "Misc/AutomationTest.h" +#include "Settings/LevelEditorPlaySettings.h" +#include "Tests/AutomationCommon.h" +#include "Tests/AutomationEditorCommon.h" + +#include "Cesium3DTileset.h" +#include "CesiumFlyToComponent.h" +#include "CesiumGeoreference.h" +#include "GlobeAwareDefaultPawn.h" +#include "GoogleTilesTestSetup.h" + +#include "CesiumLoadTestCore.h" +#include "CesiumSceneGeneration.h" +#include "CesiumTestHelpers.h" + +#include "TestRegionPolygons.h" + +#define VIEWPORT_WIDTH 1280; +#define VIEWPORT_HEIGHT 720; +// Twelve hour soak test +constexpr static double SOAK_TEST_DURATION = 60 * 60 * 12; +// The duration in seconds between each stress test iteration +constexpr static double TEST_ITERATION_DELAY = 10.0; +constexpr static float FLIGHT_TIME = 5.0f; + +// Stack of indices into TestRegionPolygons::polygons to use next +static std::stack nextPolygonIndex; + +namespace Cesium { + +FString& getLogFilePath() { + static std::optional path{}; + static const TCHAR* filename = TEXT("tiles_output.csv"); + + if (!path.has_value()) { + path = FString::Printf(TEXT("%s/%s"), *FPaths::ProjectDir(), filename); + } + + return path.value(); +} + +void countTree( + Cesium3DTilesSelection::Tile* tile, + int depth, + int& outCount, + int& outUnloaded, + int& outUnloading, + int& outContentLoading, + int& outContentLoaded, + int& outDone) { + /*std::string indentation(depth, '\t'); + UE_LOG( + LogCesium, + Display, + TEXT("%s- tile load state %d"), + UTF8_TO_TCHAR(indentation.c_str()), + tile->getState());*/ + + outCount++; + gsl::span tiles = tile->getChildren(); + for (Cesium3DTilesSelection::Tile& child : tiles) { + switch (child.getState()) { + case Cesium3DTilesSelection::TileLoadState::Unloaded: + outUnloaded++; + break; + case Cesium3DTilesSelection::TileLoadState::ContentLoading: + outContentLoading++; + break; + case Cesium3DTilesSelection::TileLoadState::ContentLoaded: + outContentLoaded++; + break; + case Cesium3DTilesSelection::TileLoadState::Unloading: + outUnloading++; + break; + case Cesium3DTilesSelection::TileLoadState::Done: + outDone++; + break; + } + countTree( + &child, + depth + 1, + outCount, + outUnloaded, + outUnloading, + outContentLoading, + outContentLoaded, + outDone); + } +} + +void logDebug(ACesium3DTileset* tilesetActor) { + Cesium3DTilesSelection::Tileset* tileset = tilesetActor->GetTileset(); + int numTiles = 0, numUnloaded = 0, numUnloading = 0, numContentLoading = 0, + numContentLoaded = 0, numDone = 0; + countTree( + tileset->getRootTile(), + 0, + numTiles, + numUnloaded, + numUnloading, + numContentLoading, + numContentLoaded, + numDone); + + FGenericPlatformMemoryStats stats = FPlatformMemory::GetStats(); + + IPlatformFile& file = FPlatformFileManager::Get().GetPlatformFile(); + IFileHandle* handle = file.OpenWrite(*getLogFilePath(), true); + assert(handle); + + std::stringstream outstream; + + outstream << static_cast(FPlatformTime::Seconds()) << "," << numTiles << "," << numUnloaded + << "," << numUnloading << "," << numContentLoading << "," + << numContentLoaded << "," << numDone << "," << stats.UsedVirtual + << std::endl; + + std::string str = outstream.str(); + handle->Write(reinterpret_cast(str.c_str()), str.length()); + handle->Flush(); + delete handle; + + UE_LOG( + LogCesium, + Display, + TEXT( + "Tileset has %d tiles in tree (%d unloaded, %d unloading, %d content loading, %d content loaded, %d done)"), + numTiles, + numUnloaded, + numUnloading, + numContentLoading, + numContentLoaded, + numDone); +} + +void fillWithRandomIndices() { + // Create a vector with every index + std::vector indices; + for (int i = 0; i < TEST_REGION_POLYGONS_COUNT; i++) { + indices.push_back(i); + } + + // Shuffle indices + std::default_random_engine rng{}; + std::shuffle(indices.begin(), indices.end(), rng); + + // Push shuffled indices onto stack + for (int idx : indices) { + nextPolygonIndex.push(idx); + } +} + +// Since this shares a name with the global defined in Google3dTilesLoadTest, we +// tell the compiler to look for the variable there instead. +extern LoadTestContext gLoadTestContext; + +DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER( + FFlyToRandomLocationCommand, + LoadTestContext&, + context); + +bool FFlyToRandomLocationCommand::Update() { + + if (!GEditor->IsPlaySessionInProgress()) { + return true; + } + + logDebug(context.playContext.tilesets.at(0)); + + UCesiumFlyToComponent* flyTo = + context.playContext.pawn->FindComponentByClass(); + + flyTo->Duration = FLIGHT_TIME; + + FVector pawnPosition = context.playContext.pawn->GetActorLocation(); + FVector llhPosition = + context.playContext.georeference + ->TransformUnrealPositionToLongitudeLatitudeHeight(pawnPosition); + + if (nextPolygonIndex.empty()) { + fillWithRandomIndices(); + } + + const int nextIndex = nextPolygonIndex.top(); + nextPolygonIndex.pop(); + + FVector targetLlh = TestRegionPolygons::polygons[nextIndex].GetRandomPoint(); + targetLlh.Z = 1000.0f; + + // Start the flight + context.playContext.pawn + ->FlyToLocationLongitudeLatitudeHeight(targetLlh, 0, 0, false); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FGoogleTilesStressTest, + "Cesium.Performance.StressTest.GoogleTiles", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::StressFilter) + +bool FGoogleTilesStressTest::RunTest(const FString& Parameters) { + + LoadTestContext& context = gLoadTestContext; + + context.reset(); + + UE_LOG(LogCesium, Display, TEXT("Creating common world objects...")); + createCommonWorldObjects(context.creationContext); + + UE_LOG(LogCesium, Display, TEXT("Setting up location...")); + GoogleTilesTestSetup::setupForGoogleplex(context.creationContext); + ACesium3DTileset* tileset = context.creationContext.tilesets.at(0); + tileset->MaximumCachedBytes = 0; + context.creationContext.trackForPlay(); + + // Let the editor viewports see the same thing the test will + context.creationContext.syncWorldCamera(); + + context.creationContext.refreshTilesets(); + + ADD_LATENT_AUTOMATION_COMMAND(FWaitForShadersToFinishCompiling); + + // Queue play in editor and set desired viewport size + FRequestPlaySessionParams Params; + Params.WorldType = EPlaySessionWorldType::PlayInEditor; + Params.EditorPlaySettings = NewObject(); + Params.EditorPlaySettings->NewWindowWidth = VIEWPORT_WIDTH; + Params.EditorPlaySettings->NewWindowHeight = VIEWPORT_HEIGHT; + Params.EditorPlaySettings->EnableGameSound = false; + GEditor->RequestPlaySession(Params); + + ADD_LATENT_AUTOMATION_COMMAND( + InitForPlayWhenReady(context.creationContext, context.playContext)); + + // Wait to show distinct gap in profiler + ADD_LATENT_AUTOMATION_COMMAND(FWaitLatentCommand(1.0f)); + + int numFlights = static_cast( + SOAK_TEST_DURATION / (FLIGHT_TIME + TEST_ITERATION_DELAY)); + + for (int i = 0; i < numFlights; i++) { + // Give it some time for the tiles to load where we are + ADD_LATENT_AUTOMATION_COMMAND(FWaitLatentCommand(TEST_ITERATION_DELAY)); + ADD_LATENT_AUTOMATION_COMMAND(FFlyToRandomLocationCommand(context)); + ADD_LATENT_AUTOMATION_COMMAND(FWaitLatentCommand(FLIGHT_TIME)); + } + + // End play in editor + ADD_LATENT_AUTOMATION_COMMAND(FEndPlayMapCommand()); + + ADD_LATENT_AUTOMATION_COMMAND(TestCleanupCommand(context)); + + return true; +} + +} // namespace Cesium + +#endif diff --git a/Source/CesiumRuntime/Public/CesiumFlyToComponent.h b/Source/CesiumRuntime/Public/CesiumFlyToComponent.h index 82c274aa8..0ee8aef51 100644 --- a/Source/CesiumRuntime/Public/CesiumFlyToComponent.h +++ b/Source/CesiumRuntime/Public/CesiumFlyToComponent.h @@ -198,6 +198,11 @@ class CESIUMRUNTIME_API UCesiumFlyToComponent UFUNCTION(BlueprintCallable, Category = "Cesium") void InterruptFlight(); + /** + * Returns true if a flight is currently in progress, false otherwise. + */ + bool IsFlightInProgress(); + protected: virtual void TickComponent( float DeltaTime, diff --git a/extern/cesium-native b/extern/cesium-native index 43187540a..5e4a4d44d 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit 43187540a5199d3b5fa8693fca90a1b81bf73c80 +Subproject commit 5e4a4d44d5d3bbf130da708d99bbe966c80568d3