diff --git a/Documentation/Diagrams/classes-for-3d-tiles.mmd b/Documentation/Diagrams/classes-for-3d-tiles.mmd new file mode 100644 index 000000000..93eafc314 --- /dev/null +++ b/Documentation/Diagrams/classes-for-3d-tiles.mmd @@ -0,0 +1,21 @@ +--- +config: + class: + hideEmptyMembersBox: true +--- +classDiagram +direction TB + AActor <|-- ACesium3DTileset + USceneComponent <|-- UCesiumGltfComponent + USceneComponent <|-- UStaticMeshComponent + USceneComponent <|-- UInstancedStaticMeshComponent + ICesiumPrimitive <|-- UCesiumGltfInstancedComponent + UStaticMeshComponent <|-- UCesiumGltfPrimitiveComponent + ICesiumPrimitive <|-- UCesiumGltfPrimitiveComponent + UCesiumGltfPrimitiveComponent <|-- UCesiumGltfPointsComponent + UInstancedStaticMeshComponent <|-- UCesiumGltfInstancedComponent + class AActor:::unreal + class USceneComponent:::unreal + class UStaticMeshComponent:::unreal + class UInstancedStaticMeshComponent:::unreal + classDef unreal fill:#FFE9CE, color:#543410 diff --git a/Documentation/Diagrams/texture-resource-classes.mmd b/Documentation/Diagrams/texture-resource-classes.mmd new file mode 100644 index 000000000..90d07baf6 --- /dev/null +++ b/Documentation/Diagrams/texture-resource-classes.mmd @@ -0,0 +1,23 @@ +--- +config: + class: + hideEmptyMembersBox: true +--- +classDiagram +direction TB + class FCesiumCreateNewTextureResource { + +Pixel Data + +Mip Positions + } + class FCesiumPreCreatedRHITextureResource { + +RHI Texture + } + class FCesiumUseExistingTextureResource { + +Previous FTextureResource to Wrap + } + FTextureResource <|-- FCesiumTextureResource + FCesiumTextureResource <|-- FCesiumCreateNewTextureResource + FCesiumTextureResource <|-- FCesiumPreCreatedRHITextureResource + FCesiumTextureResource <|-- FCesiumUseExistingTextureResource + class FTextureResource:::unreal + classDef unreal fill:#FFE9CE, color:#543410 diff --git a/Documentation/unreal-engine-3d-tiles.md b/Documentation/unreal-engine-3d-tiles.md new file mode 100644 index 000000000..be784fcb5 --- /dev/null +++ b/Documentation/unreal-engine-3d-tiles.md @@ -0,0 +1,77 @@ +# 3D Tiles in Unreal Engine + +The [Rendering 3D Tiles](\ref rendering-3d-tiles) page in the Cesium Native documentation explains in the abstract how Cesium Native can be used to integrate 3D Tiles rendering into an application. This page explains how Cesium for Unreal integrates 3D Tiles rendering into Unreal Engine specifically. + +## ITaskProcessor + +The implementation of [ITaskProcessor](\ref CesiumAsync::ITaskProcessor) for Unreal Engine is found in `UnrealTaskProcessor.h` and `.cpp` and is only a few lines of code. It uses Unreal's `AsyncTask` function to run the provided callback on the Unreal Engine task graph. The particular thread specifier used is `AnyBackgroundThreadNormalTask`. The meaning of this is not well documented, but we initially used `AnyThread` and found that our background work could sometimes block essential tasks related to rendering, causing frame-rate hiccups. Switching to `AnyBackgroundThreadNormalTask` slightly increased load times, but made rendering much smoother. See [CesiumGS/cesium-unreal#975](https://github.com/CesiumGS/cesium-unreal/pull/975) for further details. + +## IAssetAccessor + +`UnrealAssetAccessor` implements [IAssetAccessor](\ref CesiumAsync::IAssetAccessor) using Unreal's `HttpModule`. While this is largely straightforward and it has served us well overall, it has also been a source of quirks and performance problems. + +##### File URLs + +Unreal's HttpModule uses [libcurl](https://curl.se/libcurl/) under the hood, but the developers have chosen to disable libcurl's support for `file:///` URLs. Because our users frequently want to access 3D Tiles tileset from the local file system (in addition to the web), we have implemented custom support for file URLs in our asset accessor. It uses Unreal's `FFileHelper::LoadFileToArray` to read files, running in the `GIOThreadPool`. + +##### Configuration Parameters + +The Cesium for Unreal plugin includes `Config/Engine.ini` and `Config/Editor.ini` files to configure various aspects of Unreal's HTTP request system. See the comments in those files for an explanation of what we're changing and why. Without these tweaks, Unreal would spam the Output Log, complaining about Cesium making too many network requests. The time to download 3D Tiles files would also be much longer. + +## IPrepareRendererResources + +The implementation of the [IPrepareRendererResources](\ref Cesium3DTilesSelection::IPrepareRendererResources) interface in `UnrealPrepareRendererResources` is the heart of Cesium for Unreal. It is responsible for creating Unreal objects from 3D Tiles glTFs so that they can be rendered and interacted-with in Unreal Engine. + +The major `UObject` classes involved in 3D Tiles rendering, and their inheritance relationships, are shown in the class diagram below. The types built into Unreal Engine are shown in a different color from the ones provided with Cesium for Unreal. + +@mermaid{classes-for-3d-tiles} + +* `ACesium3DTileset`: The Actor responsible for loading a 3D Tiles tileset. On each `Tick`, it calls Cesium Native's [updateView](\ref Cesium3DTilesSelection::Tileset::updateView). +* `UCesiumGltfComponent`: Represents a single 3D Tiles tile. A `ACesium3DTileset` will have many `UCesiumGltfComponent` instances attached to it, one for each tile that is currently loaded. +* `UCesiumGltfPrimitiveComponent`: Represents a single [MeshPrimitive](\ref CesiumGltf::MeshPrimitive) within a single 3D Tiles tile (glTF). A `UCesiumGltfComponent` will usually have one or more `UCesiumGltfPrimitiveComponent` instances attached to it. +* `UCesiumGltfPointsComponent`: A more specific type of `UCesiumGltfPrimitiveComponent` that is used when the `MeshPrimitive` uses the [POINTS](\ref CesiumGltf::MeshPrimitive::Mode::POINTS) mode. That is, when it is a point cloud. +* `UCesiumGltfInstancedComponent`: An alternate representation of a glTF `MeshPrimitive` that is used when multiple copies of the mesh are rendered under the direction of the [EXT_gpu_instancing](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing) extension. + +Instances of `UCesiumGltfComponent`, `UCesiumGltfInstancedComponent`, and `UCesiumGltfPointsComponent`, along with accompanying `UStaticMesh`, `UMaterialInstanceDynamic`, and `UTexture2D` instances, are created by `UnrealPrepareRendererResources` as 3D Tiles are loaded. These `UObject`-derived classes are created on the game thread. Game thread time is a limited resource in most Unreal Engine applications, though, so we strive to do as much of the loading work as possible in background threads. + +For that reason, Cesium for Unreal takes advantage of the separate [prepareInLoadThread](\ref Cesium3DTilesSelection::IPrepareRendererResources::prepareInLoadThread) and [prepareInMainThread](\ref Cesium3DTilesSelection::IPrepareRendererResources::prepareInMainThread) methods on `IPrepareRendererResources`. + +> [!note] +> Recent versions of Unreal Engine reportedly do allow creating UObjects in background threads, probably with some significant caveats. In the future, we should consider whether the relaxation of this limitation allows us to improve our design or performance. + +In `prepareInLoadThread`, Cesium for Unreal receives a [Model](\ref CesiumGltf::Model) from Cesium Native and creates from it a `LoadedModelResult`. This struct holds a representation of the model that is as close to "fully renderable in Unreal Engine" as we can manage without creating any `UObjects`: + +* Normals and tangents are generated, if required. +* Texture MipMaps are generated, if required. +* Physics meshes are generated, if required. +* Mesh vertex and index data for each `MeshPrimitive` are copied into an instance of Unreal's `FStaticMeshRenderData`. +* An `FCesiumTextureResource` is created for each texture. This class is derived from Unreal's `FTextureResource` and is Unreal's low-level, render-thread representation of a texture. +* Feature IDs and metadata that are made available to a material via the [UCesiumFeaturesMetadataComponent](\ref UCesiumFeaturesMetadataComponent) are turned into additional textures. + +Then, in `prepareInMainThread`, we receive the `LoadedModelResult` produced above, and create all of the `UObject` instances from it, avoiding as much as possible copying or transforming any data. + +### Multithreaded Texture Creation + +Textures are often the largest part of a 3D Tiles tileset, especially for real-world, photogrammetry-derived models. So, Cesium for Unreal takes great pains to: + +1. Avoid keeping multiple copies of a texture in CPU or GPU memory. +2. Avoid copying texture data unnecessarily, even if it's only held temporarily. +3. Create renderable textures on the GPU without using any more game thread or render thread time than is absolutely necessary. + +To that end, Cesium for Unreal's texture creation system uses some low-level, largely undocumented parts of the Unreal Engine API. This is made trickier by the fact that a single image may have multiple purposes within a glTF, or it may be shared across multiple glTF tiles in a 3D Tiles tileset. + +Textures are created near the start of `prepareInLoadThread` with calls to `ExtensionImageAssetUnreal::getOrCreate`. This method expects that multiple threads may call it simultaneously on a single [ImageAsset](\ref CesiumGltf::ImageAsset). This happens when the two threads are loading two different tiles that happen to share a single image. It uses a mutex to ensure that only the first thread adds an `ExtensionImageAssetUnreal` and then proceeds to load the image. Any other threads will instead get the existing `ExtensionImageAssetUnreal`, which includes a [SharedFuture](\ref CesiumAsync::SharedFuture) that will resolve when the first thread has finished loading the image. + +This system ensures that a) only one thread loads the image, and b) other threads can asynchronously wait for the image to be loaded, without blocking any threads while they're waiting. + +The thread that is doing the actual loading will create a new instance of a class derived from `FCesiumTextureResource` for the `ImageAsset`. + +@mermaid{texture-resource-classes} + +For Unreal Render Hardware Interfaces (RHI) that support asynchronous texture upload (`GRHISupportsAsyncTextureCreation` is set), which is currently only Direct3D 11 and 12, the instance will be of type `FCesiumPreCreatedRHITextureResource`. The GPU upload will happen immediately under the control of the worker thread with a call to `RHIAsyncCreateTexture2D`. + +For RHIs that don't support async texture upload, the new instance will be of type `FCesiumCreateNewTextureResource` and a command will be queued to the render thread to do the texture upload with a call to `RHICreateTexture`. In either case, the CPU-side pixel data, which is now owned by the `FCesiumTextureResource`, is freed once the GPU upload is complete. + +In Unreal Engine, an `FTextureResource` encapsulates both the GPU texture resource (represented as `FRHITexture`), but also details such as the sampling mode (nearest, linear, mipmaps), as well as whether or not to treat it as sRGB. This is unfortunate because we would like to have just one copy of each set of pixel data, even if that pixel data happens to be sampled differently when it's used in different contexts. Fortunately, we can create multiple `FTextureResource` instances that reference a single `FRHITexture` via reference counting. + +For simplicity, we always do this, even when there is no sharing. The initial `FCesiumTextureResource` that is created can be viewed as a representation of the glTF [Image](\ref CesiumGltf::Image). Then, we create an instance of `FCesiumUseExistingTextureResource` for each glTF [Texture](\ref CesiumGltf::Texture). The `FCesiumUseExistingTextureResource` wraps the `FCesiumCreateNewTextureResource` or `FCesiumPreCreatedRHITextureResource` instance created previously and brings the sampler settings that are appropriate for the context. diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 824ad94eb..7e6618583 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -5,7 +5,6 @@ #include "Camera/CameraTypes.h" #include "Camera/PlayerCameraManager.h" #include "Cesium3DTilesSelection/EllipsoidTilesetLoader.h" -#include "Cesium3DTilesSelection/IPrepareRendererResources.h" #include "Cesium3DTilesSelection/Tile.h" #include "Cesium3DTilesSelection/TilesetLoadFailureDetails.h" #include "Cesium3DTilesSelection/TilesetOptions.h" @@ -26,15 +25,12 @@ #include "CesiumGltfPointsSceneProxyUpdater.h" #include "CesiumGltfPrimitiveComponent.h" #include "CesiumIonClient/Connection.h" -#include "CesiumLifetime.h" #include "CesiumRasterOverlay.h" #include "CesiumRuntime.h" #include "CesiumRuntimeSettings.h" -#include "CesiumTextureUtility.h" #include "CesiumTileExcluder.h" #include "CesiumViewExtension.h" #include "Components/SceneCaptureComponent2D.h" -#include "CreateGltfOptions.h" #include "Engine/Engine.h" #include "Engine/LocalPlayer.h" #include "Engine/SceneCapture2D.h" @@ -43,7 +39,6 @@ #include "Engine/TextureRenderTarget2D.h" #include "Engine/World.h" #include "EngineUtils.h" -#include "ExtensionImageAssetUnreal.h" #include "GameFramework/PlayerController.h" #include "Kismet/GameplayStatics.h" #include "LevelSequenceActor.h" @@ -51,6 +46,7 @@ #include "Math/UnrealMathUtility.h" #include "PixelFormat.h" #include "StereoRendering.h" +#include "UnrealPrepareRendererResources.h" #include "VecMath.h" #include #include @@ -810,252 +806,6 @@ void ACesium3DTileset::NotifyHit( // std::cout << "Hit face index 2: " << detailedHit.FaceIndex << std::endl; } -class UnrealResourcePreparer - : public Cesium3DTilesSelection::IPrepareRendererResources { -public: - UnrealResourcePreparer(ACesium3DTileset* pActor) : _pActor(pActor) {} - - virtual CesiumAsync::Future< - Cesium3DTilesSelection::TileLoadResultAndRenderResources> - prepareInLoadThread( - const CesiumAsync::AsyncSystem& asyncSystem, - Cesium3DTilesSelection::TileLoadResult&& tileLoadResult, - const glm::dmat4& transform, - const std::any& rendererOptions) override { - CreateGltfOptions::CreateModelOptions options(std::move(tileLoadResult)); - if (!options.pModel) { - return asyncSystem.createResolvedFuture( - Cesium3DTilesSelection::TileLoadResultAndRenderResources{ - std::move(options.tileLoadResult), - nullptr}); - } - - options.alwaysIncludeTangents = this->_pActor->GetAlwaysIncludeTangents(); - options.createPhysicsMeshes = this->_pActor->GetCreatePhysicsMeshes(); - - options.ignoreKhrMaterialsUnlit = - this->_pActor->GetIgnoreKhrMaterialsUnlit(); - - if (this->_pActor->_featuresMetadataDescription) { - options.pFeaturesMetadataDescription = - &(*this->_pActor->_featuresMetadataDescription); - } else if (this->_pActor->_metadataDescription_DEPRECATED) { - options.pEncodedMetadataDescription_DEPRECATED = - &(*this->_pActor->_metadataDescription_DEPRECATED); - } - - const CesiumGeospatial::Ellipsoid& ellipsoid = tileLoadResult.ellipsoid; - - CesiumAsync::Future - pHalfFuture = UCesiumGltfComponent::CreateOffGameThread( - asyncSystem, - transform, - std::move(options), - ellipsoid); - - return MoveTemp(pHalfFuture) - .thenImmediately( - [](UCesiumGltfComponent::CreateOffGameThreadResult&& result) - -> Cesium3DTilesSelection::TileLoadResultAndRenderResources { - return Cesium3DTilesSelection::TileLoadResultAndRenderResources{ - std::move(result.TileLoadResult), - result.HalfConstructed.Release()}; - }); - } - - virtual void* prepareInMainThread( - Cesium3DTilesSelection::Tile& tile, - void* pLoadThreadResult) override { - Cesium3DTilesSelection::TileContent& content = tile.getContent(); - if (content.isRenderContent()) { - TUniquePtr pHalf( - reinterpret_cast( - pLoadThreadResult)); - Cesium3DTilesSelection::TileRenderContent& renderContent = - *content.getRenderContent(); - return UCesiumGltfComponent::CreateOnGameThread( - renderContent.getModel(), - this->_pActor, - std::move(pHalf), - _pActor->GetCesiumTilesetToUnrealRelativeWorldTransform(), - this->_pActor->GetMaterial(), - this->_pActor->GetTranslucentMaterial(), - this->_pActor->GetWaterMaterial(), - this->_pActor->GetCustomDepthParameters(), - tile, - this->_pActor->GetCreateNavCollision()); - } - // UE_LOG(LogCesium, VeryVerbose, TEXT("No content for tile")); - return nullptr; - } - - virtual void free( - Cesium3DTilesSelection::Tile& tile, - void* pLoadThreadResult, - void* pMainThreadResult) noexcept override { - if (pLoadThreadResult) { - UCesiumGltfComponent::HalfConstructed* pHalf = - reinterpret_cast( - pLoadThreadResult); - delete pHalf; - } else if (pMainThreadResult) { - UCesiumGltfComponent* pGltf = - reinterpret_cast(pMainThreadResult); - CesiumLifetime::destroyComponentRecursively(pGltf); - } - } - - virtual void* prepareRasterInLoadThread( - CesiumGltf::ImageAsset& image, - const std::any& rendererOptions) override { - auto ppOptions = - std::any_cast(&rendererOptions); - check(ppOptions != nullptr && *ppOptions != nullptr); - if (ppOptions == nullptr || *ppOptions == nullptr) { - return nullptr; - } - - auto pOptions = *ppOptions; - - if (pOptions->useMipmaps) { - std::optional errorMessage = - CesiumGltfReader::ImageDecoder::generateMipMaps(image); - if (errorMessage) { - UE_LOG( - LogCesium, - Warning, - TEXT("%s"), - UTF8_TO_TCHAR(errorMessage->c_str())); - } - } - - // TODO: sRGB should probably be configurable on the raster overlay. - bool sRGB = true; - - const ExtensionImageAssetUnreal& extension = - ExtensionImageAssetUnreal::getOrCreate( - CesiumAsync::AsyncSystem(nullptr), // TODO - image, - sRGB, - pOptions->useMipmaps, - std::nullopt); - - // Because raster overlay images are never shared (at least currently!), the - // future should already be resolved by the time we get here. - check(extension.getFuture().isReady()); - - auto texture = CesiumTextureUtility::loadTextureAnyThreadPart( - image, - TextureAddress::TA_Clamp, - TextureAddress::TA_Clamp, - pOptions->filter, - pOptions->useMipmaps, - pOptions->group, - sRGB, - std::nullopt); - - return texture.Release(); - } - - virtual void* prepareRasterInMainThread( - CesiumRasterOverlays::RasterOverlayTile& rasterTile, - void* pLoadThreadResult) override { - TUniquePtr pLoadedTexture{ - static_cast( - pLoadThreadResult)}; - - if (!pLoadedTexture) { - return nullptr; - } - - CesiumUtility::IntrusivePointer< - CesiumTextureUtility::ReferenceCountedUnrealTexture> - pTexture = CesiumTextureUtility::loadTextureGameThreadPart( - pLoadedTexture.Get()); - if (!pTexture) { - return nullptr; - } - - // Don't let this ReferenceCountedUnrealTexture be destroyed when the - // intrusive pointer goes out of scope. - pTexture->addReference(); - return pTexture.get(); - } - - virtual void freeRaster( - const CesiumRasterOverlays::RasterOverlayTile& rasterTile, - void* pLoadThreadResult, - void* pMainThreadResult) noexcept override { - if (pLoadThreadResult) { - CesiumTextureUtility::LoadedTextureResult* pLoadedTexture = - static_cast( - pLoadThreadResult); - delete pLoadedTexture; - } - - if (pMainThreadResult) { - CesiumTextureUtility::ReferenceCountedUnrealTexture* pTexture = - static_cast( - pMainThreadResult); - pTexture->releaseReference(); - } - } - - virtual void attachRasterInMainThread( - const Cesium3DTilesSelection::Tile& tile, - int32_t overlayTextureCoordinateID, - const CesiumRasterOverlays::RasterOverlayTile& rasterTile, - void* pMainThreadRendererResources, - const glm::dvec2& translation, - const glm::dvec2& scale) override { - const Cesium3DTilesSelection::TileContent& content = tile.getContent(); - const Cesium3DTilesSelection::TileRenderContent* pRenderContent = - content.getRenderContent(); - if (pMainThreadRendererResources != nullptr && pRenderContent != nullptr) { - UCesiumGltfComponent* pGltfContent = - reinterpret_cast( - pRenderContent->getRenderResources()); - if (pGltfContent) { - pGltfContent->AttachRasterTile( - tile, - rasterTile, - static_cast( - pMainThreadRendererResources) - ->getUnrealTexture(), - translation, - scale, - overlayTextureCoordinateID); - } - } - } - - virtual void detachRasterInMainThread( - const Cesium3DTilesSelection::Tile& tile, - int32_t overlayTextureCoordinateID, - const CesiumRasterOverlays::RasterOverlayTile& rasterTile, - void* pMainThreadRendererResources) noexcept override { - const Cesium3DTilesSelection::TileContent& content = tile.getContent(); - const Cesium3DTilesSelection::TileRenderContent* pRenderContent = - content.getRenderContent(); - if (pRenderContent) { - UCesiumGltfComponent* pGltfContent = - reinterpret_cast( - pRenderContent->getRenderResources()); - if (pMainThreadRendererResources != nullptr && pGltfContent != nullptr) { - pGltfContent->DetachRasterTile( - tile, - rasterTile, - static_cast( - pMainThreadRendererResources) - ->getUnrealTexture()); - } - } - } - -private: - ACesium3DTileset* _pActor; -}; - void ACesium3DTileset::UpdateLoadStatus() { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::UpdateLoadStatus) @@ -1216,7 +966,7 @@ void ACesium3DTileset::LoadTileset() { Cesium3DTilesSelection::TilesetExternals externals{ pAssetAccessor, - std::make_shared(this), + std::make_shared(this), asyncSystem, pCreditSystem ? pCreditSystem->GetExternalCreditSystem() : nullptr, spdlog::default_logger(), diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index c899d71c8..5522f8136 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -91,7 +91,7 @@ static uint32_t nextMaterialId = 0; namespace { class HalfConstructedReal : public UCesiumGltfComponent::HalfConstructed { public: - LoadModelResult loadModelResult{}; + LoadedModelResult loadModelResult{}; }; } // namespace @@ -440,7 +440,7 @@ static TUniquePtr loadTexture( static void applyWaterMask( CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive, - LoadPrimitiveResult& primitiveResult) { + LoadedPrimitiveResult& primitiveResult) { // Initialize water mask if needed. auto onlyWaterIt = primitive.extras.find("OnlyWater"); auto onlyLandIt = primitive.extras.find("OnlyLand"); @@ -920,7 +920,7 @@ static void updateTextureCoordinatesForMetadata_DEPRECATED( PRAGMA_ENABLE_DEPRECATION_WARNINGS static void loadPrimitiveFeaturesMetadata( - LoadPrimitiveResult& primitiveResult, + LoadedPrimitiveResult& primitiveResult, const CreatePrimitiveOptions& options, CesiumGltf::Model& model, CesiumGltf::MeshPrimitive& primitive, @@ -973,7 +973,7 @@ static void loadPrimitiveFeaturesMetadata( const CreateGltfOptions::CreateModelOptions* pModelOptions = options.pMeshOptions->pNodeOptions->pModelOptions; - const LoadGltfResult::LoadModelResult* pModelResult = + const LoadGltfResult::LoadedModelResult* pModelResult = options.pMeshOptions->pNodeOptions->pHalfConstructedModelResult; primitiveResult.Features = @@ -1140,7 +1140,7 @@ constexpr glm::dmat4 yInvertMatrix = { template static void loadPrimitive( - LoadPrimitiveResult& primitiveResult, + LoadedPrimitiveResult& primitiveResult, const glm::dmat4x4& transform, const CreatePrimitiveOptions& options, const CesiumGltf::Accessor& positionAccessor, @@ -1752,7 +1752,7 @@ static void loadPrimitive( } static void loadIndexedPrimitive( - LoadPrimitiveResult& primitiveResult, + LoadedPrimitiveResult& primitiveResult, const glm::dmat4x4& transform, const CreatePrimitiveOptions& options, const CesiumGltf::Accessor& positionAccessor, @@ -1815,7 +1815,7 @@ static void loadIndexedPrimitive( } static void loadPrimitive( - LoadPrimitiveResult& result, + LoadedPrimitiveResult& result, const glm::dmat4x4& transform, const CreatePrimitiveOptions& options, const CesiumGeospatial::Ellipsoid& ellipsoid) { @@ -1872,7 +1872,7 @@ static void loadPrimitive( } static void loadMesh( - std::optional& result, + std::optional& result, const glm::dmat4x4& transform, CreateMeshOptions& options, const CesiumGeospatial::Ellipsoid& ellipsoid) { @@ -1882,7 +1882,7 @@ static void loadMesh( CesiumGltf::Model& model = *options.pNodeOptions->pModelOptions->pModel; CesiumGltf::Mesh& mesh = model.meshes[options.meshIndex]; - result = LoadMeshResult(); + result = LoadedMeshResult(); result->primitiveResults.reserve(mesh.primitives.size()); for (size_t i = 0; i < mesh.primitives.size(); i++) { CreatePrimitiveOptions primitiveOptions = {&options, &*result, i}; @@ -1921,7 +1921,7 @@ inline constexpr bool is_int_quat_v = is_int_quat::value; static void loadInstancingData( const CesiumGltf::Model& model, const CesiumGltf::Node& node, - LoadNodeResult& result, + LoadedNodeResult& result, const CesiumGltf::ExtensionExtMeshGpuInstancing* pGpuInstancing, const CesiumGltf::ExtensionExtInstanceFeatures* pInstanceFeatures) { auto getInstanceAccessor = @@ -2049,7 +2049,7 @@ static void loadInstancingData( } static void loadNode( - std::vector& loadNodeResults, + std::vector& loadNodeResults, const glm::dmat4x4& transform, CreateNodeOptions& options, const CesiumGeospatial::Ellipsoid& ellipsoid) { @@ -2077,7 +2077,7 @@ static void loadNode( CesiumGltf::Model& model = *options.pModelOptions->pModel; const CesiumGltf::Node& node = *options.pNode; - LoadNodeResult& result = loadNodeResults.emplace_back(); + LoadedNodeResult& result = loadNodeResults.emplace_back(); glm::dmat4x4 nodeTransform = transform; @@ -2200,8 +2200,9 @@ void applyGltfUpAxisTransform( } // namespace -static void -loadModelMetadata(LoadModelResult& result, const CreateModelOptions& options) { +static void loadModelMetadata( + LoadedModelResult& result, + const CreateModelOptions& options) { CesiumGltf::Model& model = *options.pModel; CesiumGltf::ExtensionModelExtStructuralMetadata* pModelMetadata = @@ -2364,7 +2365,7 @@ loadModelAnyThreadPart( &options, &pHalf->loadModelResult, nullptr}; - LoadNodeResult& dummyNodeResult = + LoadedNodeResult& dummyNodeResult = pHalf->loadModelResult.nodeResults.emplace_back(); CreateMeshOptions meshOptions = { &dummyNodeOptions, @@ -2409,7 +2410,7 @@ bool applyTexture( static void SetGltfParameterValues( CesiumGltf::Model& model, - LoadPrimitiveResult& loadResult, + LoadedPrimitiveResult& loadResult, const CesiumGltf::Material& material, const CesiumGltf::MaterialPBRMetallicRoughness& pbr, UMaterialInstanceDynamic* pMaterial, @@ -2637,7 +2638,7 @@ static void SetGltfParameterValues( void SetWaterParameterValues( CesiumGltf::Model& model, - LoadPrimitiveResult& loadResult, + LoadedPrimitiveResult& loadResult, UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, int32 index) { @@ -2667,7 +2668,7 @@ void SetWaterParameterValues( static void SetFeaturesMetadataParameterValues( const CesiumGltf::Model& model, UCesiumGltfComponent& gltfComponent, - LoadPrimitiveResult& loadResult, + LoadedPrimitiveResult& loadResult, UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, int32 index) { @@ -2748,7 +2749,7 @@ PRAGMA_DISABLE_DEPRECATION_WARNINGS static void SetMetadataParameterValues_DEPRECATED( const CesiumGltf::Model& model, UCesiumGltfComponent& gltfComponent, - LoadPrimitiveResult& loadResult, + LoadedPrimitiveResult& loadResult, UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, int32 index) { @@ -2952,7 +2953,7 @@ void addInstanceFeatureIds( static void loadPrimitiveGameThreadPart( CesiumGltf::Model& model, UCesiumGltfComponent* pGltf, - LoadPrimitiveResult& loadResult, + LoadedPrimitiveResult& loadResult, const glm::dmat4x4& cesiumToUnrealTransform, const Cesium3DTilesSelection::Tile& tile, bool createNavCollision, @@ -3347,9 +3348,10 @@ UCesiumGltfComponent::CreateOffGameThread( encodeMetadataGameThreadPart(*Gltf->EncodedMetadata_DEPRECATED); } - for (LoadNodeResult& node : pReal->loadModelResult.nodeResults) { + for (LoadedNodeResult& node : pReal->loadModelResult.nodeResults) { if (node.meshResult) { - for (LoadPrimitiveResult& primitive : node.meshResult->primitiveResults) { + for (LoadedPrimitiveResult& primitive : + node.meshResult->primitiveResults) { loadPrimitiveGameThreadPart( model, Gltf, diff --git a/Source/CesiumRuntime/Private/CesiumTextureResource.cpp b/Source/CesiumRuntime/Private/CesiumTextureResource.cpp index 148bcf6f7..eadb74de7 100644 --- a/Source/CesiumRuntime/Private/CesiumTextureResource.cpp +++ b/Source/CesiumRuntime/Private/CesiumTextureResource.cpp @@ -12,15 +12,11 @@ namespace { /** * A Cesium texture resource that uses an already-created `FRHITexture`. This is * used when `GRHISupportsAsyncTextureCreation` is true and so we were already - * able to create the FRHITexture in a worker thread. It is also used when a - * single glTF `Image` is referenced by multiple glTF `Texture` instances. We - * only need one `FRHITexture` is this case, but we need multiple - * `FTextureResource` instances to support the different sampler settings that - * are likely used in the different textures. + * able to create the FRHITexture in a worker thread. */ -class FCesiumUseExistingTextureResource : public FCesiumTextureResource { +class FCesiumPreCreatedRHITextureResource : public FCesiumTextureResource { public: - FCesiumUseExistingTextureResource( + FCesiumPreCreatedRHITextureResource( FTextureRHIRef existingTexture, TextureGroup textureGroup, uint32 width, @@ -34,6 +30,19 @@ class FCesiumUseExistingTextureResource : public FCesiumTextureResource { uint32 extData, bool isPrimary); +protected: + virtual FTextureRHIRef InitializeTextureRHI() override; +}; + +/** + * A Cesium texture resource that wraps an existing one and uses the same RHI + * texture resource. This allows a single glTF `Image` to be referenced by + * multiple glTF `Texture` instances. We only need one `FRHITexture` in this + * case, but we need multiple `FTextureResource` instances to support the + * different sampler settings that are likely used in the different textures. + */ +class FCesiumUseExistingTextureResource : public FCesiumTextureResource { +public: FCesiumUseExistingTextureResource( const TSharedPtr& pExistingTexture, TextureGroup textureGroup, @@ -356,7 +365,7 @@ void FCesiumTextureResourceDeleter::operator()(FCesiumTextureResource* p) { // textureReference->SetName( // FName(UTF8_TO_TCHAR(imageCesium.getUniqueAssetId().c_str()))); auto pResult = - FCesiumTextureResourceUniquePtr(new FCesiumUseExistingTextureResource( + FCesiumTextureResourceUniquePtr(new FCesiumPreCreatedRHITextureResource( textureReference, textureGroup, imageCesium.width, @@ -568,7 +577,7 @@ FName FCesiumTextureResource::TextureGroupStatFNames[TEXTUREGROUP_MAX] = { #endif // #if STATS -FCesiumUseExistingTextureResource::FCesiumUseExistingTextureResource( +FCesiumPreCreatedRHITextureResource::FCesiumPreCreatedRHITextureResource( FTextureRHIRef existingTexture, TextureGroup textureGroup, uint32 width, @@ -592,11 +601,14 @@ FCesiumUseExistingTextureResource::FCesiumUseExistingTextureResource( sRGB, useMipsIfAvailable, extData, - isPrimary), - _pExistingTexture(nullptr) { + isPrimary) { this->TextureRHI = std::move(existingTexture); } +FTextureRHIRef FCesiumPreCreatedRHITextureResource::InitializeTextureRHI() { + return this->TextureRHI; +} + FCesiumUseExistingTextureResource::FCesiumUseExistingTextureResource( const TSharedPtr& pExistingTexture, TextureGroup textureGroup, @@ -625,11 +637,7 @@ FCesiumUseExistingTextureResource::FCesiumUseExistingTextureResource( _pExistingTexture(pExistingTexture) {} FTextureRHIRef FCesiumUseExistingTextureResource::InitializeTextureRHI() { - if (this->_pExistingTexture) { - return this->_pExistingTexture->TextureRHI; - } else { - return this->TextureRHI; - } + return this->_pExistingTexture->TextureRHI; } FCesiumCreateNewTextureResource::FCesiumCreateNewTextureResource( diff --git a/Source/CesiumRuntime/Private/CreateGltfOptions.h b/Source/CesiumRuntime/Private/CreateGltfOptions.h index c809652e7..7af0e9e3f 100644 --- a/Source/CesiumRuntime/Private/CreateGltfOptions.h +++ b/Source/CesiumRuntime/Private/CreateGltfOptions.h @@ -49,19 +49,20 @@ struct CreateModelOptions { struct CreateNodeOptions { const CreateModelOptions* pModelOptions = nullptr; - const LoadGltfResult::LoadModelResult* pHalfConstructedModelResult = nullptr; + const LoadGltfResult::LoadedModelResult* pHalfConstructedModelResult = + nullptr; const CesiumGltf::Node* pNode = nullptr; }; struct CreateMeshOptions { const CreateNodeOptions* pNodeOptions = nullptr; - const LoadGltfResult::LoadNodeResult* pHalfConstructedNodeResult = nullptr; + const LoadGltfResult::LoadedNodeResult* pHalfConstructedNodeResult = nullptr; int32_t meshIndex = -1; }; struct CreatePrimitiveOptions { const CreateMeshOptions* pMeshOptions = nullptr; - const LoadGltfResult::LoadMeshResult* pHalfConstructedMeshResult = nullptr; + const LoadGltfResult::LoadedMeshResult* pHalfConstructedMeshResult = nullptr; int32_t primitiveIndex = -1; }; } // namespace CreateGltfOptions diff --git a/Source/CesiumRuntime/Private/LoadGltfResult.h b/Source/CesiumRuntime/Private/LoadGltfResult.h index 6d01fe2db..85ebf2abf 100644 --- a/Source/CesiumRuntime/Private/LoadGltfResult.h +++ b/Source/CesiumRuntime/Private/LoadGltfResult.h @@ -37,13 +37,13 @@ namespace LoadGltfResult { * * This type is move-only due to the use of TUniquePtr. */ -struct LoadPrimitiveResult { +struct LoadedPrimitiveResult { #pragma region Temporary render data - LoadPrimitiveResult(const LoadPrimitiveResult&) = delete; + LoadedPrimitiveResult(const LoadedPrimitiveResult&) = delete; - LoadPrimitiveResult() {} - LoadPrimitiveResult(LoadPrimitiveResult&& other) = default; + LoadedPrimitiveResult() {} + LoadedPrimitiveResult(LoadedPrimitiveResult&& other) = default; /** * The render data. This is populated so it can be set on the static mesh @@ -158,26 +158,26 @@ struct LoadPrimitiveResult { /** * Represents the result of loading a glTF mesh on a game thread. */ -struct LoadMeshResult { - LoadMeshResult() {} +struct LoadedMeshResult { + LoadedMeshResult() {} - LoadMeshResult(const LoadMeshResult&) = delete; - LoadMeshResult(LoadMeshResult&& other) = default; - LoadMeshResult& operator=(LoadMeshResult&& other) = default; + LoadedMeshResult(const LoadedMeshResult&) = delete; + LoadedMeshResult(LoadedMeshResult&& other) = default; + LoadedMeshResult& operator=(LoadedMeshResult&& other) = default; - std::vector primitiveResults{}; + std::vector primitiveResults{}; }; /** * Represents the result of loading a glTF node on a game thread. */ -struct LoadNodeResult { - LoadNodeResult() {} +struct LoadedNodeResult { + LoadedNodeResult() {} - LoadNodeResult(const LoadNodeResult&) = delete; - LoadNodeResult(LoadNodeResult&& other) = default; + LoadedNodeResult(const LoadedNodeResult&) = delete; + LoadedNodeResult(LoadedNodeResult&& other) = default; - std::optional meshResult = std::nullopt; + std::optional meshResult = std::nullopt; /** * Array of instance transforms, if any. */ @@ -195,8 +195,8 @@ struct LoadNodeResult { * Temporarily holds data that needs to be transferred to the corresponding * CesiumGltfComponent after it is created on the main thread. */ -struct LoadModelResult { - std::vector nodeResults{}; +struct LoadedModelResult { + std::vector nodeResults{}; // Parses the root EXT_structural_metadata extension. FCesiumModelMetadata Metadata{}; diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp new file mode 100644 index 000000000..de6b0c91b --- /dev/null +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -0,0 +1,252 @@ +#include "UnrealPrepareRendererResources.h" +#include "Cesium3DTileset.h" +#include "CesiumGltfComponent.h" +#include "CesiumLifetime.h" +#include "CesiumRasterOverlay.h" +#include "CesiumRuntime.h" +#include "CreateGltfOptions.h" +#include "ExtensionImageAssetUnreal.h" +#include +#include +#include +#include +#include + +UnrealPrepareRendererResources::UnrealPrepareRendererResources( + ACesium3DTileset* pActor) + : _pActor(pActor) {} + +CesiumAsync::Future +UnrealPrepareRendererResources::prepareInLoadThread( + const CesiumAsync::AsyncSystem& asyncSystem, + Cesium3DTilesSelection::TileLoadResult&& tileLoadResult, + const glm::dmat4& transform, + const std::any& rendererOptions) { + CreateGltfOptions::CreateModelOptions options(std::move(tileLoadResult)); + if (!options.pModel) { + return asyncSystem.createResolvedFuture( + Cesium3DTilesSelection::TileLoadResultAndRenderResources{ + std::move(options.tileLoadResult), + nullptr}); + } + + options.alwaysIncludeTangents = this->_pActor->GetAlwaysIncludeTangents(); + options.createPhysicsMeshes = this->_pActor->GetCreatePhysicsMeshes(); + + options.ignoreKhrMaterialsUnlit = this->_pActor->GetIgnoreKhrMaterialsUnlit(); + + if (this->_pActor->_featuresMetadataDescription) { + options.pFeaturesMetadataDescription = + &(*this->_pActor->_featuresMetadataDescription); + } else if (this->_pActor->_metadataDescription_DEPRECATED) { + options.pEncodedMetadataDescription_DEPRECATED = + &(*this->_pActor->_metadataDescription_DEPRECATED); + } + + const CesiumGeospatial::Ellipsoid& ellipsoid = tileLoadResult.ellipsoid; + + CesiumAsync::Future + pHalfFuture = UCesiumGltfComponent::CreateOffGameThread( + asyncSystem, + transform, + std::move(options), + ellipsoid); + + return MoveTemp(pHalfFuture) + .thenImmediately( + [](UCesiumGltfComponent::CreateOffGameThreadResult&& result) + -> Cesium3DTilesSelection::TileLoadResultAndRenderResources { + return Cesium3DTilesSelection::TileLoadResultAndRenderResources{ + std::move(result.TileLoadResult), + result.HalfConstructed.Release()}; + }); +} + +void* UnrealPrepareRendererResources::prepareInMainThread( + Cesium3DTilesSelection::Tile& tile, + void* pLoadThreadResult) { + Cesium3DTilesSelection::TileContent& content = tile.getContent(); + if (content.isRenderContent()) { + TUniquePtr pHalf( + reinterpret_cast( + pLoadThreadResult)); + Cesium3DTilesSelection::TileRenderContent& renderContent = + *content.getRenderContent(); + return UCesiumGltfComponent::CreateOnGameThread( + renderContent.getModel(), + this->_pActor, + std::move(pHalf), + _pActor->GetCesiumTilesetToUnrealRelativeWorldTransform(), + this->_pActor->GetMaterial(), + this->_pActor->GetTranslucentMaterial(), + this->_pActor->GetWaterMaterial(), + this->_pActor->GetCustomDepthParameters(), + tile, + this->_pActor->GetCreateNavCollision()); + } + // UE_LOG(LogCesium, VeryVerbose, TEXT("No content for tile")); + return nullptr; +} + +void UnrealPrepareRendererResources::free( + Cesium3DTilesSelection::Tile& tile, + void* pLoadThreadResult, + void* pMainThreadResult) noexcept { + if (pLoadThreadResult) { + UCesiumGltfComponent::HalfConstructed* pHalf = + reinterpret_cast( + pLoadThreadResult); + delete pHalf; + } else if (pMainThreadResult) { + UCesiumGltfComponent* pGltf = + reinterpret_cast(pMainThreadResult); + CesiumLifetime::destroyComponentRecursively(pGltf); + } +} + +void* UnrealPrepareRendererResources::prepareRasterInLoadThread( + CesiumGltf::ImageAsset& image, + const std::any& rendererOptions) { + auto ppOptions = + std::any_cast(&rendererOptions); + check(ppOptions != nullptr && *ppOptions != nullptr); + if (ppOptions == nullptr || *ppOptions == nullptr) { + return nullptr; + } + + auto pOptions = *ppOptions; + + if (pOptions->useMipmaps) { + std::optional errorMessage = + CesiumGltfReader::ImageDecoder::generateMipMaps(image); + if (errorMessage) { + UE_LOG( + LogCesium, + Warning, + TEXT("%s"), + UTF8_TO_TCHAR(errorMessage->c_str())); + } + } + + // TODO: sRGB should probably be configurable on the raster overlay. + bool sRGB = true; + + const ExtensionImageAssetUnreal& extension = + ExtensionImageAssetUnreal::getOrCreate( + CesiumAsync::AsyncSystem(nullptr), // TODO + image, + sRGB, + pOptions->useMipmaps, + std::nullopt); + + // Because raster overlay images are never shared (at least currently!), the + // future should already be resolved by the time we get here. + check(extension.getFuture().isReady()); + + auto texture = CesiumTextureUtility::loadTextureAnyThreadPart( + image, + TextureAddress::TA_Clamp, + TextureAddress::TA_Clamp, + pOptions->filter, + pOptions->useMipmaps, + pOptions->group, + sRGB, + std::nullopt); + + return texture.Release(); +} + +void* UnrealPrepareRendererResources::prepareRasterInMainThread( + CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pLoadThreadResult) { + TUniquePtr pLoadedTexture{ + static_cast( + pLoadThreadResult)}; + + if (!pLoadedTexture) { + return nullptr; + } + + CesiumUtility::IntrusivePointer< + CesiumTextureUtility::ReferenceCountedUnrealTexture> + pTexture = + CesiumTextureUtility::loadTextureGameThreadPart(pLoadedTexture.Get()); + if (!pTexture) { + return nullptr; + } + + // Don't let this ReferenceCountedUnrealTexture be destroyed when the + // intrusive pointer goes out of scope. + pTexture->addReference(); + return pTexture.get(); +} + +void UnrealPrepareRendererResources::freeRaster( + const CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pLoadThreadResult, + void* pMainThreadResult) noexcept { + if (pLoadThreadResult) { + CesiumTextureUtility::LoadedTextureResult* pLoadedTexture = + static_cast( + pLoadThreadResult); + delete pLoadedTexture; + } + + if (pMainThreadResult) { + CesiumTextureUtility::ReferenceCountedUnrealTexture* pTexture = + static_cast( + pMainThreadResult); + pTexture->releaseReference(); + } +} + +void UnrealPrepareRendererResources::attachRasterInMainThread( + const Cesium3DTilesSelection::Tile& tile, + int32_t overlayTextureCoordinateID, + const CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pMainThreadRendererResources, + const glm::dvec2& translation, + const glm::dvec2& scale) { + const Cesium3DTilesSelection::TileContent& content = tile.getContent(); + const Cesium3DTilesSelection::TileRenderContent* pRenderContent = + content.getRenderContent(); + if (pMainThreadRendererResources != nullptr && pRenderContent != nullptr) { + UCesiumGltfComponent* pGltfContent = + reinterpret_cast( + pRenderContent->getRenderResources()); + if (pGltfContent) { + pGltfContent->AttachRasterTile( + tile, + rasterTile, + static_cast( + pMainThreadRendererResources) + ->getUnrealTexture(), + translation, + scale, + overlayTextureCoordinateID); + } + } +} + +void UnrealPrepareRendererResources::detachRasterInMainThread( + const Cesium3DTilesSelection::Tile& tile, + int32_t overlayTextureCoordinateID, + const CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pMainThreadRendererResources) noexcept { + const Cesium3DTilesSelection::TileContent& content = tile.getContent(); + const Cesium3DTilesSelection::TileRenderContent* pRenderContent = + content.getRenderContent(); + if (pRenderContent) { + UCesiumGltfComponent* pGltfContent = + reinterpret_cast( + pRenderContent->getRenderResources()); + if (pMainThreadRendererResources != nullptr && pGltfContent != nullptr) { + pGltfContent->DetachRasterTile( + tile, + rasterTile, + static_cast( + pMainThreadRendererResources) + ->getUnrealTexture()); + } + } +} diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.h b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.h new file mode 100644 index 000000000..48508a6c0 --- /dev/null +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.h @@ -0,0 +1,62 @@ +#pragma once + +#include + +class ACesium3DTileset; + +/** + * An implementation of Cesium Native's IPrepareRendererResources that creates + * Unreal objects for 3D Tiles tiles and raster overlays. + */ +class UnrealPrepareRendererResources + : public Cesium3DTilesSelection::IPrepareRendererResources { +public: + UnrealPrepareRendererResources(ACesium3DTileset* pActor); + + virtual CesiumAsync::Future< + Cesium3DTilesSelection::TileLoadResultAndRenderResources> + prepareInLoadThread( + const CesiumAsync::AsyncSystem& asyncSystem, + Cesium3DTilesSelection::TileLoadResult&& tileLoadResult, + const glm::dmat4& transform, + const std::any& rendererOptions) override; + + virtual void* prepareInMainThread( + Cesium3DTilesSelection::Tile& tile, + void* pLoadThreadResult) override; + + virtual void free( + Cesium3DTilesSelection::Tile& tile, + void* pLoadThreadResult, + void* pMainThreadResult) noexcept override; + + virtual void* prepareRasterInLoadThread( + CesiumGltf::ImageAsset& image, + const std::any& rendererOptions) override; + + virtual void* prepareRasterInMainThread( + CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pLoadThreadResult) override; + + virtual void freeRaster( + const CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pLoadThreadResult, + void* pMainThreadResult) noexcept override; + + virtual void attachRasterInMainThread( + const Cesium3DTilesSelection::Tile& tile, + int32_t overlayTextureCoordinateID, + const CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pMainThreadRendererResources, + const glm::dvec2& translation, + const glm::dvec2& scale) override; + + virtual void detachRasterInMainThread( + const Cesium3DTilesSelection::Tile& tile, + int32_t overlayTextureCoordinateID, + const CesiumRasterOverlays::RasterOverlayTile& rasterTile, + void* pMainThreadRendererResources) noexcept override; + +private: + ACesium3DTileset* _pActor; +}; diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index b43084e25..50de411ff 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -1108,7 +1108,7 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { /** * This method is not supposed to be called by clients. It is currently - * only required by the UnrealResourcePreparer. + * only required by the UnrealPrepareRendererResources. * * @internal * See {@link @@ -1309,6 +1309,6 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { int32 _tilesetsBeingDestroyed; - friend class UnrealResourcePreparer; + friend class UnrealPrepareRendererResources; friend class UCesiumGltfPointsComponent; }; diff --git a/Source/CesiumRuntime/Public/CesiumBingMapsRasterOverlay.h b/Source/CesiumRuntime/Public/CesiumBingMapsRasterOverlay.h index 656954740..92f04f45b 100644 --- a/Source/CesiumRuntime/Public/CesiumBingMapsRasterOverlay.h +++ b/Source/CesiumRuntime/Public/CesiumBingMapsRasterOverlay.h @@ -22,7 +22,7 @@ enum class EBingMapsStyle : uint8 { * A raster overlay that directly accesses Bing Maps. If you're using Bing Maps * via Cesium ion, use the "Cesium ion Raster Overlay" component instead. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumBingMapsRasterOverlay : public UCesiumRasterOverlay { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumCartographicPolygon.h b/Source/CesiumRuntime/Public/CesiumCartographicPolygon.h index 770bdf314..6d4a81c1e 100644 --- a/Source/CesiumRuntime/Public/CesiumCartographicPolygon.h +++ b/Source/CesiumRuntime/Public/CesiumCartographicPolygon.h @@ -18,7 +18,7 @@ * A spline-based polygon actor used to rasterize 2D polygons on top of * Cesium 3D Tileset actors. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API ACesiumCartographicPolygon : public AActor { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumEncodedMetadataComponent.h b/Source/CesiumRuntime/Public/CesiumEncodedMetadataComponent.h index 4e4ad3b30..aef91d524 100644 --- a/Source/CesiumRuntime/Public/CesiumEncodedMetadataComponent.h +++ b/Source/CesiumRuntime/Public/CesiumEncodedMetadataComponent.h @@ -267,6 +267,7 @@ struct CESIUMRUNTIME_API FMetadataDescription { * "Auto Fill" button. Once a selection of desired metadata is made, the * boiler-plate material code to access the selected properties can be * auto-generated using the "Generate Material" button. + * @deprecated Use UCesiumFeaturesMetadataComponent instead. */ UCLASS(Deprecated) class CESIUMRUNTIME_API UDEPRECATED_CesiumEncodedMetadataComponent diff --git a/Source/CesiumRuntime/Public/CesiumFeaturesMetadataComponent.h b/Source/CesiumRuntime/Public/CesiumFeaturesMetadataComponent.h index 114a53394..a204a080a 100644 --- a/Source/CesiumRuntime/Public/CesiumFeaturesMetadataComponent.h +++ b/Source/CesiumRuntime/Public/CesiumFeaturesMetadataComponent.h @@ -323,7 +323,7 @@ struct CESIUMRUNTIME_API FCesiumFeaturesMetadataDescription { * boiler-plate material code to access the selected properties can be * auto-generated using the "Generate Material" button. */ -UCLASS(ClassGroup = (Cesium), Meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, Meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumFeaturesMetadataComponent : public UActorComponent { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumPolygonRasterOverlay.h b/Source/CesiumRuntime/Public/CesiumPolygonRasterOverlay.h index 728ecc231..09c5ac3e8 100644 --- a/Source/CesiumRuntime/Public/CesiumPolygonRasterOverlay.h +++ b/Source/CesiumRuntime/Public/CesiumPolygonRasterOverlay.h @@ -17,7 +17,7 @@ class RasterizedPolygonsTileExcluder; * This is useful for clipping out parts of a tileset, for adding a water effect * in an area, and for many other purposes. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumPolygonRasterOverlay : public UCesiumRasterOverlay { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumSubLevelComponent.h b/Source/CesiumRuntime/Public/CesiumSubLevelComponent.h index c781b919d..21b0a0fa2 100644 --- a/Source/CesiumRuntime/Public/CesiumSubLevelComponent.h +++ b/Source/CesiumRuntime/Public/CesiumSubLevelComponent.h @@ -43,7 +43,7 @@ class UCesiumSubLevelSwitcherComponent; * sub-level's "Load Radius" that sub-level will be activated. If multiple * sub-levels are in range, only the closest one will be activated. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumSubLevelComponent : public UActorComponent { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumTileMapServiceRasterOverlay.h b/Source/CesiumRuntime/Public/CesiumTileMapServiceRasterOverlay.h index be0aaa938..dca53363a 100644 --- a/Source/CesiumRuntime/Public/CesiumTileMapServiceRasterOverlay.h +++ b/Source/CesiumRuntime/Public/CesiumTileMapServiceRasterOverlay.h @@ -12,7 +12,7 @@ * you're using a Tile Map Service via Cesium ion, use the "Cesium ion Raster * Overlay" component instead. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumTileMapServiceRasterOverlay : public UCesiumRasterOverlay { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumUrlTemplateRasterOverlay.h b/Source/CesiumRuntime/Public/CesiumUrlTemplateRasterOverlay.h index dc2c396bd..5fb429a90 100644 --- a/Source/CesiumRuntime/Public/CesiumUrlTemplateRasterOverlay.h +++ b/Source/CesiumRuntime/Public/CesiumUrlTemplateRasterOverlay.h @@ -27,7 +27,7 @@ enum class ECesiumUrlTemplateRasterOverlayProjection : uint8 { /** * A raster overlay that loads tiles from a templated URL. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumUrlTemplateRasterOverlay : public UCesiumRasterOverlay { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumWebMapServiceRasterOverlay.h b/Source/CesiumRuntime/Public/CesiumWebMapServiceRasterOverlay.h index e052e34cc..2d2658228 100644 --- a/Source/CesiumRuntime/Public/CesiumWebMapServiceRasterOverlay.h +++ b/Source/CesiumRuntime/Public/CesiumWebMapServiceRasterOverlay.h @@ -11,7 +11,7 @@ * A raster overlay that directly accesses a Web Map Service (WMS) server. * https://www.ogc.org/standards/wms */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumWebMapServiceRasterOverlay : public UCesiumRasterOverlay { GENERATED_BODY() diff --git a/Source/CesiumRuntime/Public/CesiumWebMapTileServiceRasterOverlay.h b/Source/CesiumRuntime/Public/CesiumWebMapTileServiceRasterOverlay.h index 6cc2ced7e..c0de5947f 100644 --- a/Source/CesiumRuntime/Public/CesiumWebMapTileServiceRasterOverlay.h +++ b/Source/CesiumRuntime/Public/CesiumWebMapTileServiceRasterOverlay.h @@ -29,7 +29,7 @@ enum class ECesiumWebMapTileServiceRasterOverlayProjection : uint8 { * If you're using a Web Map Tile Service via Cesium ion, use the "Cesium ion * Raster Overlay" component instead. */ -UCLASS(ClassGroup = (Cesium), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent)) class CESIUMRUNTIME_API UCesiumWebMapTileServiceRasterOverlay : public UCesiumRasterOverlay { GENERATED_BODY()