#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()); } } }