From 8b927015b765eaa9776587f9eee9a272ab693348 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 8 May 2025 21:31:46 +0200 Subject: [PATCH 01/33] [enhancement#1658] mesh, material and tile loading callbacks https://github.com/CesiumGS/cesium-unreal/issues/1658 --- CHANGES.md | 2 + .../CesiumRuntime/Private/Cesium3DTileset.cpp | 12 ++ .../Private/CesiumGltfComponent.cpp | 109 +++++++++++++++--- .../Private/CesiumGltfComponent.h | 16 ++- .../Private/CesiumGltfPrimitiveComponent.cpp | 52 +++++++++ .../Private/CesiumGltfPrimitiveComponent.h | 16 +++ .../Private/CesiumMeshBuildCallbacks.cpp | 34 ++++++ .../CesiumRuntime/Private/CesiumPrimitive.h | 16 ++- .../CesiumRuntime/Private/CreateGltfOptions.h | 11 ++ Source/CesiumRuntime/Private/LoadGltfResult.h | 8 ++ .../UnrealPrepareRendererResources.cpp | 10 ++ Source/CesiumRuntime/Public/Cesium3DTileset.h | 40 +++++++ .../CesiumRuntime/Public/CesiumLoadedTile.h | 50 ++++++++ .../Public/CesiumMeshBuildCallbacks.h | 104 +++++++++++++++++ extern/cesium-native | 2 +- 15 files changed, 461 insertions(+), 21 deletions(-) create mode 100644 Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp create mode 100644 Source/CesiumRuntime/Public/CesiumLoadedTile.h create mode 100644 Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h diff --git a/CHANGES.md b/CHANGES.md index 6704d14ca..904dafda3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,8 @@ - Added a Cesium -> Geocoder -> Geocode Blueprint function, making it easy to query the Cesium ion geocoder. - Added `UCesiumMetadataPickingBlueprintLibrary::FindPropertyTableProperty` to search for a `FCesiumPropertyTableProperty` by name on a given `UPrimitiveComponent`. +- Added a property `bAllowMeshBuffersCPUAccess` to `ACesium3DTileset` actors to keep the buffers of Unreal meshes created by the tileset in CPU memory, in order to have access to them in-game. Defaults to false. +- Added the class `CesiumMeshBuildCallbacks`: when an implementation is registered on a tileset (with `ACesium3DTileset::SetMeshBuildCallbacks`), its functions will be called at various points in a tile's lifecycle, like when a mesh component is created, when a material is instanced, when the tile changes visibility, when it is unloaded, etc. ##### Fixes :wrench: diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 40c835f26..8a5e98e22 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -442,6 +442,14 @@ void ACesium3DTileset::SetCesiumIonServer(UCesiumIonServer* Server) { } } +void ACesium3DTileset::SetAllowMeshBuffersCPUAccess( + bool InMeshBuffersCPUAccess) { + if (bAllowMeshBuffersCPUAccess != InMeshBuffersCPUAccess) { + this->bAllowMeshBuffersCPUAccess = InMeshBuffersCPUAccess; + this->DestroyTileset(); + } +} + void ACesium3DTileset::SetMaximumScreenSpaceError( double InMaximumScreenSpaceError) { if (MaximumScreenSpaceError != InMaximumScreenSpaceError) { @@ -2322,3 +2330,7 @@ void ACesium3DTileset::RuntimeSettingsChanged( } } #endif + +void ACesium3DTileset::SetMeshBuildCallbacks(const TWeakPtr& Callbacks) { + this->_meshBuildCallbacks = Callbacks; +} diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index ee5f911d0..64d2a04fc 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -9,6 +9,7 @@ #include "CesiumGltfPrimitiveComponent.h" #include "CesiumGltfTextures.h" #include "CesiumMaterialUserData.h" +#include "CesiumMeshBuildCallbacks.h" #include "CesiumRasterOverlays.h" #include "CesiumRuntime.h" #include "CesiumTextureUtility.h" @@ -1253,6 +1254,9 @@ static void loadPrimitive( } } + primitiveResult.MeshBuildCallbacks = + options.pMeshOptions->pNodeOptions->pModelOptions->MeshBuildCallbacks; + auto normalAccessorIt = primitive.attributes.find("NORMAL"); CesiumGltf::AccessorView normalAccessor; bool hasNormals = false; @@ -1668,6 +1672,12 @@ static void loadPrimitive( computeTangentSpace(StaticMeshBuildVertices); } + // For iTwin scene mapping mechanism (used both for Synchro 4D schedules and + // selection highlight), we need to access vertex data from the CPU (in + // packaged game, if we don't set this flag, the data can become inaccessible + // at any time...) + const bool& bNeedsCPUAccess = options.pMeshOptions->pNodeOptions->pModelOptions->allowMeshBuffersCPUAccess; + { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::InitBuffers) @@ -1679,12 +1689,12 @@ static void loadPrimitive( LODResources.VertexBuffers.PositionVertexBuffer.Init( StaticMeshBuildVertices, - false); + bNeedsCPUAccess); FColorVertexBuffer& ColorVertexBuffer = LODResources.VertexBuffers.ColorVertexBuffer; if (hasVertexColors) { - ColorVertexBuffer.Init(StaticMeshBuildVertices, false); + ColorVertexBuffer.Init(StaticMeshBuildVertices, bNeedsCPUAccess); } uint32 numberOfTextureCoordinates = @@ -1697,7 +1707,7 @@ static void loadPrimitive( vertexBuffer.Init( StaticMeshBuildVertices.Num(), numberOfTextureCoordinates, - false); + bNeedsCPUAccess); // Manually copy the vertices into the buffer. We do this because UE 5.3 // and 5.4 have a bug where the overload of `FStaticMeshVertexBuffer::Init` @@ -1744,6 +1754,9 @@ static void loadPrimitive( { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::SetIndices) + if (bNeedsCPUAccess) { + LODResources.IndexBuffer.TrySetAllowCPUAccess(true); + } LODResources.IndexBuffer.SetIndices( indices, StaticMeshBuildVertices.Num() >= std::numeric_limits::max() @@ -2452,7 +2465,8 @@ static void SetGltfParameterValues( const CesiumGltf::MaterialPBRMetallicRoughness& pbr, UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, - int32 index) { + int32 index, + CesiumMeshBuildCallbacks const* meshBuildCallbacks) { for (auto& textureCoordinateSet : loadResult.textureCoordinateParameters) { pMaterial->SetScalarParameterValueByInfo( FMaterialParameterInfo( @@ -2671,6 +2685,11 @@ static void SetGltfParameterValues( FMaterialParameterInfo("emissiveFactor", association, index), FVector(1.0f, 1.0f, 1.0f)); } + + // Extra material customizations + if (meshBuildCallbacks) { + meshBuildCallbacks->CustomizeGltfMaterial(material, pbr, pMaterial, association, index); + } } void SetWaterParameterValues( @@ -3130,14 +3149,34 @@ static void loadPrimitiveGameThreadPart( } #endif - UMaterialInstanceDynamic* pMaterial; + // Move this right now: CreateMaterial may need them! + // "Safe" even though loadResult is still used later, because the methods used + // during material setup (SetGltfParameterValues, etc.) below do not use these + // members. + primData.Features = std::move(loadResult.Features); + primData.Metadata = std::move(loadResult.Metadata); + + UMaterialInstanceDynamic* pMaterial = nullptr; + TSharedPtr MeshBuildCallbacks = + loadResult.MeshBuildCallbacks.Pin(); { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::SetupMaterial) - - pMaterial = UMaterialInstanceDynamic::Create( - pBaseMaterial, - nullptr, - ImportedSlotName); + ensure(pBaseMaterial); + if (MeshBuildCallbacks) { + // Possibility to override the material for this primitive + pMaterial = MeshBuildCallbacks->CreateMaterial( + *pCesiumPrimitive, + pBaseMaterial, + nullptr, + ImportedSlotName); + } + ensure(pBaseMaterial); + if (!pMaterial) { + pMaterial = UMaterialInstanceDynamic::Create( + pBaseMaterial, + nullptr, + ImportedSlotName); + } pMaterial->SetFlags( RF_Transient | RF_DuplicateTransient | RF_TextExportTransient); @@ -3148,7 +3187,8 @@ static void loadPrimitiveGameThreadPart( pbr, pMaterial, EMaterialParameterAssociation::GlobalParameter, - INDEX_NONE); + INDEX_NONE, + MeshBuildCallbacks.Get()); SetWaterParameterValues( model, loadResult, @@ -3195,7 +3235,8 @@ static void loadPrimitiveGameThreadPart( pbr, pMaterial, EMaterialParameterAssociation::LayerParameter, - 0); + 0, + MeshBuildCallbacks.Get()); // Initialize fade uniform to fully visible, in case LOD transitions // are off. @@ -3250,9 +3291,6 @@ static void loadPrimitiveGameThreadPart( } } - primData.Features = std::move(loadResult.Features); - primData.Metadata = std::move(loadResult.Metadata); - primData.EncodedFeatures = std::move(loadResult.EncodedFeatures); primData.EncodedMetadata = std::move(loadResult.EncodedMetadata); @@ -3328,6 +3366,11 @@ static void loadPrimitiveGameThreadPart( TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::RegisterComponent) pMesh->RegisterComponent(); } + + // Call the observer callback (if any) once all is done + if (MeshBuildCallbacks) { + MeshBuildCallbacks->OnMeshConstructed(*pGltf, *pCesiumPrimitive); + } } /*static*/ CesiumAsync::Future @@ -3352,7 +3395,7 @@ UCesiumGltfComponent::CreateOffGameThread( UMaterialInterface* pBaseTranslucentMaterial, UMaterialInterface* pBaseWaterMaterial, FCustomDepthParameters CustomDepthParameters, - const Cesium3DTilesSelection::Tile& tile, + Cesium3DTilesSelection::Tile& tile, bool createNavCollision) { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::LoadModel) @@ -3366,6 +3409,7 @@ UCesiumGltfComponent::CreateOffGameThread( // } UCesiumGltfComponent* Gltf = NewObject(pTilesetActor); + Gltf->pTile = &tile; Gltf->SetMobility(pTilesetActor->GetRootComponent()->Mobility); Gltf->SetFlags(RF_Transient | RF_DuplicateTransient | RF_TextExportTransient); @@ -3394,10 +3438,12 @@ UCesiumGltfComponent::CreateOffGameThread( encodeMetadataGameThreadPart(*Gltf->EncodedMetadata_DEPRECATED); } + LoadGltfResult::LoadedPrimitiveResult* pAnyPrimResult = nullptr; for (LoadedNodeResult& node : pReal->loadModelResult.nodeResults) { if (node.meshResult) { for (LoadedPrimitiveResult& primitive : node.meshResult->primitiveResults) { + pAnyPrimResult = &primitive; loadPrimitiveGameThreadPart( model, Gltf, @@ -3412,11 +3458,28 @@ UCesiumGltfComponent::CreateOffGameThread( } } + if (pAnyPrimResult && pAnyPrimResult->MeshBuildCallbacks.IsValid()) { + pAnyPrimResult->MeshBuildCallbacks.Pin()->OnTileConstructed( + tile.getTileID()); + Gltf->VisibilityChangedObserver = + [MeshBuildCallbacks = pAnyPrimResult->MeshBuildCallbacks, + TileId = tile.getTileID()](bool visible) { + if (MeshBuildCallbacks.IsValid()) + MeshBuildCallbacks.Pin()->OnVisibilityChanged(TileId, visible); + }; + } + Gltf->SetVisibility(false, true); Gltf->SetCollisionEnabled(ECollisionEnabled::NoCollision); return Gltf; } +void UCesiumGltfComponent::OnVisibilityChanged() { + USceneComponent::OnVisibilityChanged(); + if (VisibilityChangedObserver) + VisibilityChangedObserver(GetVisibleFlag()); +} + UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() { // Structure to hold one-time initialization struct FConstructorStatics { @@ -3447,6 +3510,20 @@ UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() { PrimaryComponentTick.bCanEverTick = false; } +const FCesiumModelMetadata& UCesiumGltfComponent::GetModelMetadata() const { + return Metadata; +} + +const Cesium3DTilesSelection::TileID& UCesiumGltfComponent::GetTileID() const { + return pTile->getTileID(); +} + +void UCesiumGltfComponent::SetRenderReady(bool bToggle) { + if (pTile) { + pTile->setRenderEngineReadiness(bToggle); + } +} + void UCesiumGltfComponent::UpdateTransformFromCesium( const glm::dmat4& cesiumToUnrealTransform) { for (USceneComponent* pSceneComponent : this->GetAttachChildren()) { diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index 848a82e5f..eb217488c 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -5,6 +5,7 @@ #include "Cesium3DTilesSelection/Tile.h" #include "Cesium3DTileset.h" #include "CesiumEncodedMetadataUtility.h" +#include "CesiumLoadedTile.h" #include "CesiumModelMetadata.h" #include "Components/PrimitiveComponent.h" #include "Components/SceneComponent.h" @@ -12,6 +13,7 @@ #include "CustomDepthParameters.h" #include "EncodedFeaturesMetadata.h" #include "Interfaces/IHttpRequest.h" +#include "Templates/Function.h" #include #include #include @@ -56,7 +58,7 @@ struct FRasterOverlayTile { }; UCLASS() -class UCesiumGltfComponent : public USceneComponent { +class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { GENERATED_BODY() public: @@ -87,7 +89,7 @@ class UCesiumGltfComponent : public USceneComponent { UMaterialInterface* BaseTranslucentMaterial, UMaterialInterface* BaseWaterMaterial, FCustomDepthParameters CustomDepthParameters, - const Cesium3DTilesSelection::Tile& tile, + Cesium3DTilesSelection::Tile& tile, bool createNavCollision); UCesiumGltfComponent(); @@ -104,6 +106,8 @@ class UCesiumGltfComponent : public USceneComponent { UPROPERTY(EditAnywhere, Category = "Rendering") FCustomDepthParameters CustomDepthParameters{}; + Cesium3DTilesSelection::Tile* pTile = nullptr; + FCesiumModelMetadata Metadata{}; EncodedFeaturesMetadata::EncodedModelMetadata EncodedMetadata{}; @@ -131,10 +135,18 @@ class UCesiumGltfComponent : public USceneComponent { virtual void SetCollisionEnabled(ECollisionEnabled::Type NewType); virtual void BeginDestroy() override; + virtual void OnVisibilityChanged() override; + + // from ICesiumLoadedTile + const FCesiumModelMetadata& GetModelMetadata() const override; + const Cesium3DTilesSelection::TileID& GetTileID() const override; + void SetRenderReady(bool bToggle) override; void UpdateFade(float fadePercentage, bool fadingIn); private: UPROPERTY() UTexture2D* Transparent1x1 = nullptr; + + TFunction VisibilityChangedObserver; }; diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp index 68951e5f9..54145dd32 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp @@ -159,6 +159,33 @@ UCesiumGltfPrimitiveComponent::getPrimitiveData() const { return _cesiumData; } +UStaticMeshComponent& UCesiumGltfPrimitiveComponent::GetMeshComponent() { + return *this; +} + +const FCesiumModelMetadata& +UCesiumGltfPrimitiveComponent::GetModelMetadata() const { + // Not GetAttachParent(): not yet attached (eg. when calling + // CesiumMeshBuildCallbacks::CreateMaterial) + return Cast(GetOuter())->GetModelMetadata(); +} + +const Cesium3DTilesSelection::TileID& +UCesiumGltfPrimitiveComponent::GetTileID() const { + return Cast(GetOuter())->GetTileID(); +} + +std::optional +UCesiumGltfPrimitiveComponent::FindTexCoordIndexForGltfAttribute( + int32_t accessorIndex) const { + auto uvIndexIt = + getPrimitiveData().GltfToUnrealTexCoordMap.find(accessorIndex); + if (uvIndexIt != getPrimitiveData().GltfToUnrealTexCoordMap.end()) + return uvIndexIt->second; + else + return std::nullopt; +} + CesiumPrimitiveData& UCesiumGltfInstancedComponent::getPrimitiveData() { return _cesiumData; } @@ -167,3 +194,28 @@ const CesiumPrimitiveData& UCesiumGltfInstancedComponent::getPrimitiveData() const { return _cesiumData; } + +UStaticMeshComponent& UCesiumGltfInstancedComponent::GetMeshComponent() { + return *this; +} + +const FCesiumModelMetadata& +UCesiumGltfInstancedComponent::GetModelMetadata() const { + return Cast(GetOuter())->GetModelMetadata(); +} + +const Cesium3DTilesSelection::TileID& +UCesiumGltfInstancedComponent::GetTileID() const { + return Cast(GetOuter())->GetTileID(); +} + +std::optional +UCesiumGltfInstancedComponent::FindTexCoordIndexForGltfAttribute( + int32_t accessorIndex) const { + auto uvIndexIt = + getPrimitiveData().GltfToUnrealTexCoordMap.find(accessorIndex); + if (uvIndexIt != getPrimitiveData().GltfToUnrealTexCoordMap.end()) + return uvIndexIt->second; + else + return std::nullopt; +} \ No newline at end of file diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h index f37b6e0a0..e75a4019e 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h @@ -41,8 +41,16 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent, void UpdateTransformFromCesium(const glm::dmat4& CesiumToUnrealTransform) override; + // from ICesiumLoadedTileBase + const FCesiumModelMetadata& GetModelMetadata() const override; + Cesium3DTilesSelection::TileID const& GetTileID() const override; + // from ICesiumPrimitive CesiumPrimitiveData& getPrimitiveData() override; const CesiumPrimitiveData& getPrimitiveData() const override; + // from ICesiumLoadedTilePrimitive + UStaticMeshComponent& GetMeshComponent() override; + std::optional + FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const override; private: CesiumPrimitiveData _cesiumData; @@ -68,8 +76,16 @@ class UCesiumGltfInstancedComponent : public UInstancedStaticMeshComponent, void UpdateTransformFromCesium(const glm::dmat4& CesiumToUnrealTransform) override; + // from ICesiumLoadedTileBase + const FCesiumModelMetadata& GetModelMetadata() const override; + Cesium3DTilesSelection::TileID const& GetTileID() const override; + // from ICesiumPrimitive CesiumPrimitiveData& getPrimitiveData() override; const CesiumPrimitiveData& getPrimitiveData() const override; + // from ICesiumLoadedTilePrimitive + UStaticMeshComponent& GetMeshComponent() override; + std::optional + FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const override; TSharedPtr pInstanceFeatures; diff --git a/Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp b/Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp new file mode 100644 index 000000000..3905f545f --- /dev/null +++ b/Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------+ +| +| $Source: CesiumMeshBuildCallbacks.cpp $ +| +| $Copyright: (c) 2024 Bentley Systems, Incorporated. All rights reserved. $ +| ++--------------------------------------------------------------------------------------*/ + +#include "CesiumMeshBuildCallbacks.h" + +#include + +CesiumMeshBuildCallbacks::CesiumMeshBuildCallbacks() {} + +CesiumMeshBuildCallbacks::~CesiumMeshBuildCallbacks() {} + +UMaterialInstanceDynamic* CesiumMeshBuildCallbacks::CreateMaterial( + ICesiumLoadedTilePrimitive& TilePrim, + UMaterialInterface*& InOut_pChosenBaseMaterial, + UObject* InOuter, + FName const& Name) { + // Default implementation: just create a new instance + return UMaterialInstanceDynamic::Create( + InOut_pChosenBaseMaterial, + InOuter, + Name); +} + +void CesiumMeshBuildCallbacks::CustomizeGltfMaterial( + CesiumGltf::Material const& /*glTFmaterial*/, + CesiumGltf::MaterialPBRMetallicRoughness const& /*pbr*/, + UMaterialInstanceDynamic* /*pMaterial*/, + EMaterialParameterAssociation /*association*/, + int32 /*index*/) const {} diff --git a/Source/CesiumRuntime/Private/CesiumPrimitive.h b/Source/CesiumRuntime/Private/CesiumPrimitive.h index da54c66ed..621859400 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitive.h +++ b/Source/CesiumRuntime/Private/CesiumPrimitive.h @@ -4,6 +4,7 @@ #include "Cesium3DTileset.h" #include "CesiumEncodedMetadataUtility.h" +#include "CesiumLoadedTile.h" #include "CesiumMetadataPrimitive.h" #include "CesiumPrimitiveFeatures.h" #include "CesiumPrimitiveMetadata.h" @@ -122,7 +123,7 @@ class CesiumPrimitiveData { }; UINTERFACE() -class UCesiumPrimitive : public UInterface { +class UCesiumPrimitive : public UCesiumLoadedTilePrimitive { GENERATED_BODY() }; @@ -135,12 +136,23 @@ class UCesiumPrimitive : public UInterface { * code reuse and make certain functions (e.g., UpdateTransformFromCesium()) * simpler. */ -class ICesiumPrimitive { +class ICesiumPrimitive : public ICesiumLoadedTilePrimitive { GENERATED_BODY() public: virtual CesiumPrimitiveData& getPrimitiveData() = 0; virtual const CesiumPrimitiveData& getPrimitiveData() const = 0; +// from ICesiumLoadedTilePrimitive: + const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const override { + return getPrimitiveData().pMeshPrimitive; + } + FCesiumPrimitiveFeatures const& GetPrimitiveFeatures() const override { + return getPrimitiveData().Features; + } + FCesiumPrimitiveMetadata const& GetPrimitiveMetadata() const override { + return getPrimitiveData().Metadata; + } + virtual void UpdateTransformFromCesium(const glm::dmat4& CesiumToUnrealTransform) = 0; }; diff --git a/Source/CesiumRuntime/Private/CreateGltfOptions.h b/Source/CesiumRuntime/Private/CreateGltfOptions.h index ce8c7a5ee..8369a7886 100644 --- a/Source/CesiumRuntime/Private/CreateGltfOptions.h +++ b/Source/CesiumRuntime/Private/CreateGltfOptions.h @@ -12,6 +12,8 @@ #include +class CesiumMeshBuildCallbacks; + /** * Various settings and options for loading a glTF model from a 3D Tileset. */ @@ -52,6 +54,13 @@ struct CreateModelOptions { */ bool ignoreKhrMaterialsUnlit = false; + /** Whether to configure the Unreal mesh buffers to allow access from CPU. If + * this is false, the buffers can be freed from CPU memory at any time after + * they have been moved to GPU memory. */ + bool allowMeshBuffersCPUAccess = false; + + TWeakPtr MeshBuildCallbacks = nullptr; + Cesium3DTilesSelection::TileLoadResult tileLoadResult; public: @@ -67,6 +76,8 @@ struct CreateModelOptions { alwaysIncludeTangents(other.alwaysIncludeTangents), createPhysicsMeshes(other.createPhysicsMeshes), ignoreKhrMaterialsUnlit(other.ignoreKhrMaterialsUnlit), + allowMeshBuffersCPUAccess(other.allowMeshBuffersCPUAccess), + MeshBuildCallbacks(other.MeshBuildCallbacks), tileLoadResult(std::move(other.tileLoadResult)) { pModel = std::get_if(&this->tileLoadResult.contentKind); } diff --git a/Source/CesiumRuntime/Private/LoadGltfResult.h b/Source/CesiumRuntime/Private/LoadGltfResult.h index 38cc9a0df..352884c98 100644 --- a/Source/CesiumRuntime/Private/LoadGltfResult.h +++ b/Source/CesiumRuntime/Private/LoadGltfResult.h @@ -28,6 +28,8 @@ #include #include +class CesiumMeshBuildCallbacks; + namespace LoadGltfResult { /** * Represents the result of loading a glTF primitive on a load thread. @@ -152,6 +154,12 @@ struct LoadedPrimitiveResult { */ CesiumGltf::IndexAccessorType IndexAccessor; + /** + * Optional mesh build callbacks. Called at the end of the mesh creation in + * Unreal, to let you update your own structures based on the cesium + * primitive just loaded. + */ + TWeakPtr MeshBuildCallbacks; #pragma endregion }; diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp index de6b0c91b..0e11c3f9e 100644 --- a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include UnrealPrepareRendererResources::UnrealPrepareRendererResources( @@ -32,6 +33,8 @@ UnrealPrepareRendererResources::prepareInLoadThread( options.alwaysIncludeTangents = this->_pActor->GetAlwaysIncludeTangents(); options.createPhysicsMeshes = this->_pActor->GetCreatePhysicsMeshes(); + options.allowMeshBuffersCPUAccess = + this->_pActor->GetAllowMeshBuffersCPUAccess(); options.ignoreKhrMaterialsUnlit = this->_pActor->GetIgnoreKhrMaterialsUnlit(); @@ -43,6 +46,9 @@ UnrealPrepareRendererResources::prepareInLoadThread( &(*this->_pActor->_metadataDescription_DEPRECATED); } + // propagate mesh construction callback, if any + options.MeshBuildCallbacks = this->_pActor->GetMeshBuildCallbacks(); + const CesiumGeospatial::Ellipsoid& ellipsoid = tileLoadResult.ellipsoid; CesiumAsync::Future @@ -100,6 +106,10 @@ void UnrealPrepareRendererResources::free( } else if (pMainThreadResult) { UCesiumGltfComponent* pGltf = reinterpret_cast(pMainThreadResult); + if (this->_pActor->GetMeshBuildCallbacks().IsValid()) { + this->_pActor->GetMeshBuildCallbacks().Pin()->BeforeTileDestruction( + tile.getTileID()); + } CesiumLifetime::destroyComponentRecursively(pGltf); } } diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index ce26a4617..4662c4919 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -37,6 +37,7 @@ class ACesiumCameraManager; class UCesiumBoundingVolumePoolComponent; class CesiumViewExtension; struct FCesiumCamera; +class CesiumMeshBuildCallbacks; namespace Cesium3DTilesSelection { class Tileset; @@ -340,6 +341,19 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { UFUNCTION(BlueprintCallable, Category = "Cesium") void InvalidateResolvedCameraManager(); + /** + * Whether to configure the Unreal mesh buffers to allow access from CPU. If + * this is false, the buffers can be freed from CPU memory at any time after + * they have been moved to GPU memory: set to true if you need to access these + * buffers for your game logic. + */ + UPROPERTY( + EditAnywhere, + BlueprintGetter = GetAllowMeshBuffersCPUAccess, + BlueprintSetter = SetAllowMeshBuffersCPUAccess, + Category = "Cesium") + bool bAllowMeshBuffersCPUAccess = false; + /** * The maximum number of pixels of error when rendering this tileset. * @@ -1067,6 +1081,14 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { UFUNCTION(BlueprintSetter, Category = "Cesium") void SetMaximumScreenSpaceError(double InMaximumScreenSpaceError); + UFUNCTION(BlueprintGetter, Category = "Cesium") + bool GetAllowMeshBuffersCPUAccess() const { + return bAllowMeshBuffersCPUAccess; + } + + UFUNCTION(BlueprintSetter, Category = "Cesium") + void SetAllowMeshBuffersCPUAccess(bool bMeshBuffersCPUAccess); + UFUNCTION(BlueprintGetter, Category = "Cesium|Tile Culling|Experimental") bool GetEnableOcclusionCulling() const; @@ -1257,6 +1279,21 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { */ void UpdateTransformFromCesium(); + /** + * Get the attached mesh construction callback, if any. + */ + const TWeakPtr& GetMeshBuildCallbacks() const { + return this->_meshBuildCallbacks; + } + + /** + * Set the mesh construction callback. + * Can be used to be notified when a mesh component is created from a Cesium + * primitive. + */ + void + SetMeshBuildCallbacks(const TWeakPtr& Callbacks); + private: /** * The event handler for ACesiumGeoreference::OnEllipsoidChanged. @@ -1371,6 +1408,9 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { int32 _tilesetsBeingDestroyed; + // Optional implementation of the extension callbacks + TWeakPtr _meshBuildCallbacks; + friend class UnrealPrepareRendererResources; friend class UCesiumGltfPointsComponent; }; diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h new file mode 100644 index 000000000..976b80afb --- /dev/null +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -0,0 +1,50 @@ +// Copyright 2020-2024 CesiumGS, Inc. and Contributors + +#pragma once + +#include "Cesium3DTilesSelection/Tile.h" +#include "CesiumModelMetadata.h" +#include "CesiumPrimitiveFeatures.h" +#include "CesiumPrimitiveMetadata.h" + +#include "UObject/ObjectMacros.h" + +#include "CesiumLoadedTile.generated.h" + +class UStaticMeshComponent; + +UINTERFACE() +class UCesiumLoadedTileBase : public UInterface { + GENERATED_BODY() +}; +class ICesiumLoadedTileBase { + GENERATED_BODY() +public: + virtual Cesium3DTilesSelection::TileID const& GetTileID() const = 0; + virtual FCesiumModelMetadata const& GetModelMetadata() const = 0; +}; + +UINTERFACE() +class UCesiumLoadedTile : public UCesiumLoadedTileBase { + GENERATED_BODY() +}; +class ICesiumLoadedTile : public ICesiumLoadedTileBase { + GENERATED_BODY() +public: + virtual void SetRenderReady(bool bToggle) = 0; +}; + +UINTERFACE() +class UCesiumLoadedTilePrimitive : public UCesiumLoadedTileBase { + GENERATED_BODY() +}; +// Not merged with ICesiumPrimitive because this is Public whereas ICesiumPrimitive is Private +class ICesiumLoadedTilePrimitive : public ICesiumLoadedTileBase { + GENERATED_BODY() +public: + virtual UStaticMeshComponent& GetMeshComponent() = 0; + virtual FCesiumPrimitiveFeatures const& GetPrimitiveFeatures() const = 0; + virtual FCesiumPrimitiveMetadata const& GetPrimitiveMetadata() const = 0; + virtual const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const = 0; + virtual std::optional FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const = 0; +}; diff --git a/Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h b/Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h new file mode 100644 index 000000000..d55173971 --- /dev/null +++ b/Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------+ +| +| $Source: CesiumMeshBuildCallbacks.h $ +| +| $Copyright: (c) 2024 Bentley Systems, Incorporated. All rights reserved. $ +| ++--------------------------------------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +class UMaterialInstanceDynamic; +class UMaterialInterface; +enum EMaterialParameterAssociation : int; +class UStaticMeshComponent; +class USceneComponent; +struct FCesiumModelMetadata; +struct FCesiumPrimitiveFeatures; +class ICesiumTilePrimitiveData; + +namespace CesiumGltf { +struct MeshPrimitive; +struct Material; +struct MaterialPBRMetallicRoughness; +} // namespace CesiumGltf +namespace Cesium3DTilesSelection { +class Tile; +} + +/** Extension points for customizations requiring mesh and tile properties and + * lifecycle information. All methods are called from the game thread.*/ +class CESIUMRUNTIME_API CesiumMeshBuildCallbacks { +public: + CesiumMeshBuildCallbacks(); + virtual ~CesiumMeshBuildCallbacks(); + + /** + * Allows to override the base material from which loadPrimitiveGameThreadPart + *creates a dynamic material instance for the given primitive. The method can + *optionally create the material itself, if further customizations need to be + *done before returning the material, or can let the caller function do it + *based on InOut_pChosenBaseMaterial. + * \param InOut_pChosenBaseMaterial Input passes the default chosen base + *material. Can be modified so that the caller will create the material + *instance based on the custom base material (unless this method creates the + *material itself). + * \return Material instance created, or nullptr to let the caller create it. + */ + virtual UMaterialInstanceDynamic* CreateMaterial( + ICesiumLoadedTilePrimitive& TilePrim, + UMaterialInterface*& InOut_pChosenBaseMaterial, + UObject* InOuter, + FName const& Name) = 0; + + /** + * Customize the Unreal material instance, depending on the glTF material + * definition. + */ + virtual void CustomizeGltfMaterial( + const CesiumGltf::Material& glTFmaterial, + const CesiumGltf::MaterialPBRMetallicRoughness& pbr, + UMaterialInstanceDynamic* pMaterial, + EMaterialParameterAssociation association, + int32 index) const; + + /** + * Called at the end of the static mesh component construction. + */ + virtual void OnMeshConstructed( + ICesiumLoadedTile& LoadedTile, + ICesiumLoadedTilePrimitive& TilePrim) = 0; + + /** + * Called at the end of all static mesh components' construction for a given + * tile. + */ + virtual void + OnTileConstructed(const Cesium3DTilesSelection::TileID& TileID) = 0; + + /** + * Called when changing the visibility of any UCesiumGltfComponent, ie usually + * several times per tile (when the tileset selection leads to showing or + * hiding a whole tile). + */ + virtual void OnVisibilityChanged( + const Cesium3DTilesSelection::TileID& TileID, + bool visible) = 0; + + /** + * Called before a tile is destroyed (when it is unloaded, typically). + */ + virtual void + BeforeTileDestruction(const Cesium3DTilesSelection::TileID& TileID) = 0; + +private: + static TSharedPtr Singleton; +}; diff --git a/extern/cesium-native b/extern/cesium-native index 288d9147a..55036e2a3 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit 288d9147a8ef4772564e0101deda643dac61b8bb +Subproject commit 55036e2a32a14e82cce69335d10f21a5e1cd7e0d From 6025fa9401ad0a42aecc0c946e31a392de300bbe Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Tue, 13 May 2025 21:18:50 +0200 Subject: [PATCH 02/33] Account for most of the feedback received to this day Left to do: * get rid of bNeedsCPUAccess * replace TileID by ... ? * decide about CustomizeGltfMaterial * adapt UCesium3DTilesetLifecycleEventReceiver's signatures to be implementable from a BP(??) --- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 8 +- .../Cesium3DTilesetLifecycleEventReceiver.cpp | 26 +++++ .../Private/CesiumGltfComponent.cpp | 74 ++++++------- .../Private/CesiumGltfComponent.h | 2 - .../Private/CesiumGltfPrimitiveComponent.cpp | 25 ++--- .../Private/CesiumGltfPrimitiveComponent.h | 8 +- .../Private/CesiumMeshBuildCallbacks.cpp | 34 ------ .../CesiumRuntime/Private/CesiumPrimitive.h | 4 +- .../CesiumRuntime/Private/CreateGltfOptions.h | 5 - Source/CesiumRuntime/Private/LoadGltfResult.h | 9 -- .../UnrealPrepareRendererResources.cpp | 12 +- Source/CesiumRuntime/Public/Cesium3DTileset.h | 27 ++--- .../Cesium3DTilesetLifecycleEventReceiver.h | 104 ++++++++++++++++++ .../CesiumRuntime/Public/CesiumLoadedTile.h | 34 +++--- .../Public/CesiumMeshBuildCallbacks.h | 104 ------------------ 15 files changed, 216 insertions(+), 260 deletions(-) create mode 100644 Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp delete mode 100644 Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp create mode 100644 Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h delete mode 100644 Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 8a5e98e22..ba8af4d50 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -1,6 +1,7 @@ // Copyright 2020-2024 CesiumGS, Inc. and Contributors #include "Cesium3DTileset.h" + #include "Async/Async.h" #include "Camera/CameraTypes.h" #include "Camera/PlayerCameraManager.h" @@ -48,12 +49,14 @@ #include "StereoRendering.h" #include "UnrealPrepareRendererResources.h" #include "VecMath.h" + #include #include #include #ifdef CESIUM_DEBUG_TILE_STATES #include "HAL/PlatformFileManager.h" + #include #endif @@ -2331,6 +2334,7 @@ void ACesium3DTileset::RuntimeSettingsChanged( } #endif -void ACesium3DTileset::SetMeshBuildCallbacks(const TWeakPtr& Callbacks) { - this->_meshBuildCallbacks = Callbacks; +void ACesium3DTileset::SetLifecycleEventReceiver( + ICesium3DTilesetLifecycleEventReceiver* InEventReceiver) { + this->_lifecycleEventReceiver = InEventReceiver; } diff --git a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp new file mode 100644 index 000000000..0db9d0a78 --- /dev/null +++ b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp @@ -0,0 +1,26 @@ +// Copyright 2020-2025 CesiumGS, Inc. and Contributors + +#include "Cesium3DTilesetLifecycleEventReceiver.h" + +#include "Materials/MaterialInstanceDynamic.h" + +UMaterialInstanceDynamic* +ICesium3DTilesetLifecycleEventReceiver::CreateMaterial( + ICesiumLoadedTilePrimitive& TilePrim, + UMaterialInterface* pBaseMaterial, + UObject* InOuter, + const FName& Name) { + // Default implementation: just create a new instance + return UMaterialInstanceDynamic::Create( + pBaseMaterial, + InOuter, + Name); +} + +void ICesium3DTilesetLifecycleEventReceiver::CustomizeGltfMaterial( + ICesiumLoadedTilePrimitive& TilePrim, + const CesiumGltf::Material& /*glTFmaterial*/, + const CesiumGltf::MaterialPBRMetallicRoughness& /*pbr*/, + UMaterialInstanceDynamic* /*pMaterial*/, + EMaterialParameterAssociation /*association*/, + int32 /*index*/) {} diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 64d2a04fc..8c19b096c 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -1,7 +1,9 @@ // Copyright 2020-2024 CesiumGS, Inc. and Contributors #include "CesiumGltfComponent.h" + #include "Async/Async.h" +#include "Cesium3DTilesetLifecycleEventReceiver.h" #include "CesiumCommon.h" #include "CesiumEncodedMetadataUtility.h" #include "CesiumFeatureIdSet.h" @@ -9,7 +11,6 @@ #include "CesiumGltfPrimitiveComponent.h" #include "CesiumGltfTextures.h" #include "CesiumMaterialUserData.h" -#include "CesiumMeshBuildCallbacks.h" #include "CesiumRasterOverlays.h" #include "CesiumRuntime.h" #include "CesiumTextureUtility.h" @@ -1254,9 +1255,6 @@ static void loadPrimitive( } } - primitiveResult.MeshBuildCallbacks = - options.pMeshOptions->pNodeOptions->pModelOptions->MeshBuildCallbacks; - auto normalAccessorIt = primitive.attributes.find("NORMAL"); CesiumGltf::AccessorView normalAccessor; bool hasNormals = false; @@ -1672,11 +1670,11 @@ static void loadPrimitive( computeTangentSpace(StaticMeshBuildVertices); } - // For iTwin scene mapping mechanism (used both for Synchro 4D schedules and - // selection highlight), we need to access vertex data from the CPU (in - // packaged game, if we don't set this flag, the data can become inaccessible - // at any time...) - const bool& bNeedsCPUAccess = options.pMeshOptions->pNodeOptions->pModelOptions->allowMeshBuffersCPUAccess; + // Note: there is already a representation of the geometry kept in CPU memory, + // which is the CesiumGltf::Model, so we should avoid keeping a second copy... + // (TODO: remove option) + bool bNeedsCPUAccess = options.pMeshOptions->pNodeOptions->pModelOptions + ->allowMeshBuffersCPUAccess; { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::InitBuffers) @@ -1686,7 +1684,6 @@ static void loadPrimitive( // precision when using 16-bit floats. LODResources.VertexBuffers.StaticMeshVertexBuffer.SetUseFullPrecisionUVs( true); - LODResources.VertexBuffers.PositionVertexBuffer.Init( StaticMeshBuildVertices, bNeedsCPUAccess); @@ -2459,6 +2456,7 @@ bool applyTexture( #pragma region Material Parameter setters static void SetGltfParameterValues( + ICesiumPrimitive& TilePrim, CesiumGltf::Model& model, LoadedPrimitiveResult& loadResult, const CesiumGltf::Material& material, @@ -2466,7 +2464,7 @@ static void SetGltfParameterValues( UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, int32 index, - CesiumMeshBuildCallbacks const* meshBuildCallbacks) { + ICesium3DTilesetLifecycleEventReceiver* lifecycleEventReceiver) { for (auto& textureCoordinateSet : loadResult.textureCoordinateParameters) { pMaterial->SetScalarParameterValueByInfo( FMaterialParameterInfo( @@ -2687,8 +2685,14 @@ static void SetGltfParameterValues( } // Extra material customizations - if (meshBuildCallbacks) { - meshBuildCallbacks->CustomizeGltfMaterial(material, pbr, pMaterial, association, index); + if (lifecycleEventReceiver) { + lifecycleEventReceiver->CustomizeGltfMaterial( + TilePrim, + material, + pbr, + pMaterial, + association, + index); } } @@ -3157,20 +3161,24 @@ static void loadPrimitiveGameThreadPart( primData.Metadata = std::move(loadResult.Metadata); UMaterialInstanceDynamic* pMaterial = nullptr; - TSharedPtr MeshBuildCallbacks = - loadResult.MeshBuildCallbacks.Pin(); + ICesium3DTilesetLifecycleEventReceiver* pLifecycleEventReceiver = + pTilesetActor->GetLifecycleEventReceiver(); { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::SetupMaterial) ensure(pBaseMaterial); - if (MeshBuildCallbacks) { + if (pLifecycleEventReceiver) { // Possibility to override the material for this primitive - pMaterial = MeshBuildCallbacks->CreateMaterial( + pMaterial = pLifecycleEventReceiver->CreateMaterial( *pCesiumPrimitive, pBaseMaterial, nullptr, ImportedSlotName); + if (pMaterial) { + // pMaterial created above may not have used the suggested pBaseMaterial + // passed as input + pBaseMaterial = pMaterial->Parent.Get(); + } } - ensure(pBaseMaterial); if (!pMaterial) { pMaterial = UMaterialInstanceDynamic::Create( pBaseMaterial, @@ -3181,6 +3189,7 @@ static void loadPrimitiveGameThreadPart( pMaterial->SetFlags( RF_Transient | RF_DuplicateTransient | RF_TextExportTransient); SetGltfParameterValues( + *pCesiumPrimitive, model, loadResult, material, @@ -3188,7 +3197,7 @@ static void loadPrimitiveGameThreadPart( pMaterial, EMaterialParameterAssociation::GlobalParameter, INDEX_NONE, - MeshBuildCallbacks.Get()); + pLifecycleEventReceiver); SetWaterParameterValues( model, loadResult, @@ -3229,6 +3238,7 @@ static void loadPrimitiveGameThreadPart( if (pCesiumData) { SetGltfParameterValues( + *pCesiumPrimitive, model, loadResult, material, @@ -3236,7 +3246,7 @@ static void loadPrimitiveGameThreadPart( pMaterial, EMaterialParameterAssociation::LayerParameter, 0, - MeshBuildCallbacks.Get()); + pLifecycleEventReceiver); // Initialize fade uniform to fully visible, in case LOD transitions // are off. @@ -3368,8 +3378,8 @@ static void loadPrimitiveGameThreadPart( } // Call the observer callback (if any) once all is done - if (MeshBuildCallbacks) { - MeshBuildCallbacks->OnMeshConstructed(*pGltf, *pCesiumPrimitive); + if (pLifecycleEventReceiver) { + pLifecycleEventReceiver->OnTileMeshPrimitiveConstructed(*pCesiumPrimitive); } } @@ -3438,12 +3448,10 @@ UCesiumGltfComponent::CreateOffGameThread( encodeMetadataGameThreadPart(*Gltf->EncodedMetadata_DEPRECATED); } - LoadGltfResult::LoadedPrimitiveResult* pAnyPrimResult = nullptr; for (LoadedNodeResult& node : pReal->loadModelResult.nodeResults) { if (node.meshResult) { for (LoadedPrimitiveResult& primitive : node.meshResult->primitiveResults) { - pAnyPrimResult = &primitive; loadPrimitiveGameThreadPart( model, Gltf, @@ -3457,17 +3465,7 @@ UCesiumGltfComponent::CreateOffGameThread( } } } - - if (pAnyPrimResult && pAnyPrimResult->MeshBuildCallbacks.IsValid()) { - pAnyPrimResult->MeshBuildCallbacks.Pin()->OnTileConstructed( - tile.getTileID()); - Gltf->VisibilityChangedObserver = - [MeshBuildCallbacks = pAnyPrimResult->MeshBuildCallbacks, - TileId = tile.getTileID()](bool visible) { - if (MeshBuildCallbacks.IsValid()) - MeshBuildCallbacks.Pin()->OnVisibilityChanged(TileId, visible); - }; - } + pTilesetActor->GetLifecycleEventReceiver()->OnTileConstructed(*Gltf); Gltf->SetVisibility(false, true); Gltf->SetCollisionEnabled(ECollisionEnabled::NoCollision); @@ -3476,8 +3474,10 @@ UCesiumGltfComponent::CreateOffGameThread( void UCesiumGltfComponent::OnVisibilityChanged() { USceneComponent::OnVisibilityChanged(); - if (VisibilityChangedObserver) - VisibilityChangedObserver(GetVisibleFlag()); + auto* pLifecycleEventReceiver = + Cast(GetOuter())->GetLifecycleEventReceiver(); + if (pLifecycleEventReceiver) + pLifecycleEventReceiver->OnVisibilityChanged(*this, GetVisibleFlag()); } UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() { diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index eb217488c..07a5d205a 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -147,6 +147,4 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { private: UPROPERTY() UTexture2D* Transparent1x1 = nullptr; - - TFunction VisibilityChangedObserver; }; diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp index 54145dd32..88a913a2a 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp @@ -163,18 +163,11 @@ UStaticMeshComponent& UCesiumGltfPrimitiveComponent::GetMeshComponent() { return *this; } -const FCesiumModelMetadata& -UCesiumGltfPrimitiveComponent::GetModelMetadata() const { +ICesiumLoadedTile& UCesiumGltfPrimitiveComponent::GetLoadedTile() { // Not GetAttachParent(): not yet attached (eg. when calling - // CesiumMeshBuildCallbacks::CreateMaterial) - return Cast(GetOuter())->GetModelMetadata(); + // ICesium3DTilesetLifecycleEventReceiver::CreateMaterial) + return *Cast(GetOuter()); } - -const Cesium3DTilesSelection::TileID& -UCesiumGltfPrimitiveComponent::GetTileID() const { - return Cast(GetOuter())->GetTileID(); -} - std::optional UCesiumGltfPrimitiveComponent::FindTexCoordIndexForGltfAttribute( int32_t accessorIndex) const { @@ -199,14 +192,10 @@ UStaticMeshComponent& UCesiumGltfInstancedComponent::GetMeshComponent() { return *this; } -const FCesiumModelMetadata& -UCesiumGltfInstancedComponent::GetModelMetadata() const { - return Cast(GetOuter())->GetModelMetadata(); -} - -const Cesium3DTilesSelection::TileID& -UCesiumGltfInstancedComponent::GetTileID() const { - return Cast(GetOuter())->GetTileID(); +ICesiumLoadedTile& UCesiumGltfInstancedComponent::GetLoadedTile() { + // Not GetAttachParent(): not yet attached (eg. when calling + // ICesium3DTilesetLifecycleEventReceiver::CreateMaterial) + return *Cast(GetOuter()); } std::optional diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h index e75a4019e..a47b3be3e 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h @@ -41,13 +41,11 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent, void UpdateTransformFromCesium(const glm::dmat4& CesiumToUnrealTransform) override; - // from ICesiumLoadedTileBase - const FCesiumModelMetadata& GetModelMetadata() const override; - Cesium3DTilesSelection::TileID const& GetTileID() const override; // from ICesiumPrimitive CesiumPrimitiveData& getPrimitiveData() override; const CesiumPrimitiveData& getPrimitiveData() const override; // from ICesiumLoadedTilePrimitive + ICesiumLoadedTile& GetLoadedTile() override; UStaticMeshComponent& GetMeshComponent() override; std::optional FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const override; @@ -76,13 +74,11 @@ class UCesiumGltfInstancedComponent : public UInstancedStaticMeshComponent, void UpdateTransformFromCesium(const glm::dmat4& CesiumToUnrealTransform) override; - // from ICesiumLoadedTileBase - const FCesiumModelMetadata& GetModelMetadata() const override; - Cesium3DTilesSelection::TileID const& GetTileID() const override; // from ICesiumPrimitive CesiumPrimitiveData& getPrimitiveData() override; const CesiumPrimitiveData& getPrimitiveData() const override; // from ICesiumLoadedTilePrimitive + ICesiumLoadedTile& GetLoadedTile() override; UStaticMeshComponent& GetMeshComponent() override; std::optional FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const override; diff --git a/Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp b/Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp deleted file mode 100644 index 3905f545f..000000000 --- a/Source/CesiumRuntime/Private/CesiumMeshBuildCallbacks.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*--------------------------------------------------------------------------------------+ -| -| $Source: CesiumMeshBuildCallbacks.cpp $ -| -| $Copyright: (c) 2024 Bentley Systems, Incorporated. All rights reserved. $ -| -+--------------------------------------------------------------------------------------*/ - -#include "CesiumMeshBuildCallbacks.h" - -#include - -CesiumMeshBuildCallbacks::CesiumMeshBuildCallbacks() {} - -CesiumMeshBuildCallbacks::~CesiumMeshBuildCallbacks() {} - -UMaterialInstanceDynamic* CesiumMeshBuildCallbacks::CreateMaterial( - ICesiumLoadedTilePrimitive& TilePrim, - UMaterialInterface*& InOut_pChosenBaseMaterial, - UObject* InOuter, - FName const& Name) { - // Default implementation: just create a new instance - return UMaterialInstanceDynamic::Create( - InOut_pChosenBaseMaterial, - InOuter, - Name); -} - -void CesiumMeshBuildCallbacks::CustomizeGltfMaterial( - CesiumGltf::Material const& /*glTFmaterial*/, - CesiumGltf::MaterialPBRMetallicRoughness const& /*pbr*/, - UMaterialInstanceDynamic* /*pMaterial*/, - EMaterialParameterAssociation /*association*/, - int32 /*index*/) const {} diff --git a/Source/CesiumRuntime/Private/CesiumPrimitive.h b/Source/CesiumRuntime/Private/CesiumPrimitive.h index 621859400..9b4c5fff0 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitive.h +++ b/Source/CesiumRuntime/Private/CesiumPrimitive.h @@ -146,10 +146,10 @@ class ICesiumPrimitive : public ICesiumLoadedTilePrimitive { const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const override { return getPrimitiveData().pMeshPrimitive; } - FCesiumPrimitiveFeatures const& GetPrimitiveFeatures() const override { + const FCesiumPrimitiveFeatures& GetPrimitiveFeatures() const override { return getPrimitiveData().Features; } - FCesiumPrimitiveMetadata const& GetPrimitiveMetadata() const override { + const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const override { return getPrimitiveData().Metadata; } diff --git a/Source/CesiumRuntime/Private/CreateGltfOptions.h b/Source/CesiumRuntime/Private/CreateGltfOptions.h index 8369a7886..e0a5c5094 100644 --- a/Source/CesiumRuntime/Private/CreateGltfOptions.h +++ b/Source/CesiumRuntime/Private/CreateGltfOptions.h @@ -12,8 +12,6 @@ #include -class CesiumMeshBuildCallbacks; - /** * Various settings and options for loading a glTF model from a 3D Tileset. */ @@ -59,8 +57,6 @@ struct CreateModelOptions { * they have been moved to GPU memory. */ bool allowMeshBuffersCPUAccess = false; - TWeakPtr MeshBuildCallbacks = nullptr; - Cesium3DTilesSelection::TileLoadResult tileLoadResult; public: @@ -77,7 +73,6 @@ struct CreateModelOptions { createPhysicsMeshes(other.createPhysicsMeshes), ignoreKhrMaterialsUnlit(other.ignoreKhrMaterialsUnlit), allowMeshBuffersCPUAccess(other.allowMeshBuffersCPUAccess), - MeshBuildCallbacks(other.MeshBuildCallbacks), tileLoadResult(std::move(other.tileLoadResult)) { pModel = std::get_if(&this->tileLoadResult.contentKind); } diff --git a/Source/CesiumRuntime/Private/LoadGltfResult.h b/Source/CesiumRuntime/Private/LoadGltfResult.h index 352884c98..5f2f14e50 100644 --- a/Source/CesiumRuntime/Private/LoadGltfResult.h +++ b/Source/CesiumRuntime/Private/LoadGltfResult.h @@ -28,8 +28,6 @@ #include #include -class CesiumMeshBuildCallbacks; - namespace LoadGltfResult { /** * Represents the result of loading a glTF primitive on a load thread. @@ -153,13 +151,6 @@ struct LoadedPrimitiveResult { * for computing the UV at a hit location on a primitive. */ CesiumGltf::IndexAccessorType IndexAccessor; - - /** - * Optional mesh build callbacks. Called at the end of the mesh creation in - * Unreal, to let you update your own structures based on the cesium - * primitive just loaded. - */ - TWeakPtr MeshBuildCallbacks; #pragma endregion }; diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp index 0e11c3f9e..63379040d 100644 --- a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -1,5 +1,8 @@ +// Copyright 2020-2025 CesiumGS, Inc. and Contributors + #include "UnrealPrepareRendererResources.h" #include "Cesium3DTileset.h" +#include "Cesium3DTilesetLifecycleEventReceiver.h" #include "CesiumGltfComponent.h" #include "CesiumLifetime.h" #include "CesiumRasterOverlay.h" @@ -10,7 +13,6 @@ #include #include #include -#include #include UnrealPrepareRendererResources::UnrealPrepareRendererResources( @@ -46,9 +48,6 @@ UnrealPrepareRendererResources::prepareInLoadThread( &(*this->_pActor->_metadataDescription_DEPRECATED); } - // propagate mesh construction callback, if any - options.MeshBuildCallbacks = this->_pActor->GetMeshBuildCallbacks(); - const CesiumGeospatial::Ellipsoid& ellipsoid = tileLoadResult.ellipsoid; CesiumAsync::Future @@ -106,9 +105,8 @@ void UnrealPrepareRendererResources::free( } else if (pMainThreadResult) { UCesiumGltfComponent* pGltf = reinterpret_cast(pMainThreadResult); - if (this->_pActor->GetMeshBuildCallbacks().IsValid()) { - this->_pActor->GetMeshBuildCallbacks().Pin()->BeforeTileDestruction( - tile.getTileID()); + if (auto* Receiver = this->_pActor->GetLifecycleEventReceiver()) { + Receiver->BeforeTileDestruction(*pGltf); } CesiumLifetime::destroyComponentRecursively(pGltf); } diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index 4662c4919..a07063618 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -25,19 +25,20 @@ #include #include #include -#include "Cesium3DTileset.generated.h" #ifdef CESIUM_DEBUG_TILE_STATES #include #endif +#include "Cesium3DTileset.generated.h" + class UMaterialInterface; class ACesiumCartographicSelection; class ACesiumCameraManager; class UCesiumBoundingVolumePoolComponent; class CesiumViewExtension; struct FCesiumCamera; -class CesiumMeshBuildCallbacks; +class ICesium3DTilesetLifecycleEventReceiver; namespace Cesium3DTilesSelection { class Tileset; @@ -1279,20 +1280,17 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { */ void UpdateTransformFromCesium(); - /** - * Get the attached mesh construction callback, if any. + /** Gets the optional receiver of events related to tile components' lifecycle */ - const TWeakPtr& GetMeshBuildCallbacks() const { - return this->_meshBuildCallbacks; + ICesium3DTilesetLifecycleEventReceiver* GetLifecycleEventReceiver() { + return this->_lifecycleEventReceiver; } - /** - * Set the mesh construction callback. - * Can be used to be notified when a mesh component is created from a Cesium - * primitive. - */ - void - SetMeshBuildCallbacks(const TWeakPtr& Callbacks); + /** Sets a receiver of events related to tile components' lifecycle, + * like tile primitive and material creation, tile finishing its loading cycle + * or about to unload, etc. */ + void SetLifecycleEventReceiver( + ICesium3DTilesetLifecycleEventReceiver* InEventReceiver); private: /** @@ -1408,8 +1406,7 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { int32 _tilesetsBeingDestroyed; - // Optional implementation of the extension callbacks - TWeakPtr _meshBuildCallbacks; + ICesium3DTilesetLifecycleEventReceiver* _lifecycleEventReceiver; friend class UnrealPrepareRendererResources; friend class UCesiumGltfPointsComponent; diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h new file mode 100644 index 000000000..2498e8f15 --- /dev/null +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -0,0 +1,104 @@ +// Copyright 2020-2025 CesiumGS, Inc. and Contributors + +#pragma once + +#include "Cesium3DTilesSelection/TileID.h" +#include "CesiumLoadedTile.h" +#include "UObject/ObjectMacros.h" + +#include "Cesium3DTilesetLifecycleEventReceiver.generated.h" + +class UMaterialInstanceDynamic; +class UMaterialInterface; +enum EMaterialParameterAssociation : int; + +class ICesiumLoadedTile; +class ICesiumLoadedTilePrimitive; +namespace CesiumGltf { +struct Material; +struct MaterialPBRMetallicRoughness; +} // namespace CesiumGltf + +UINTERFACE() +class UCesium3DTilesetLifecycleEventReceiver : public UInterface { + GENERATED_BODY() +}; +/** Extension points for customizations requiring mesh and tile properties and + * lifecycle information. All methods are called from the game thread.*/ +class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { + GENERATED_BODY() +public: + /** + * Allows to override the base material from which the given tile primitive's + *material instance will be created. The default implementation of this method + *can be used to create the material when no customization is needed. + * @param TilePrim Loaded tile primitive for which a material is needed + * @param pDefaultBaseMaterial Default chosen base material. May be ignored if + *the method chooses to create the mesh material based on a custom base + *material. + * @param Outer The outer for the new material, as used by creation functions + *like NewObject + * @param Name The name for the new material, as used by creation functions + *like NewObject + * @return Material instance created. If null, a material will be created by + *the caller based on the pBaseMaterial passed, ie. as if this method had not + *been called. + */ + virtual UMaterialInstanceDynamic* CreateMaterial( + ICesiumLoadedTilePrimitive& TilePrim, + UMaterialInterface* pDefaultBaseMaterial, + UObject* Outer, + const FName& Name) = 0; + + /** + * Customize the Unreal material instance, depending on the glTF material + * definition. + * @param TilePrim Loaded tile primitive to which the material applies + * @param glTFmaterial Parameters of the glTF material for the primitive + * @param glTFmaterial Parameters for this primitive's material defining the + * metallic-roughness material model from Physically-Based Rendering (PBR) + * methodology + * @param pMaterial Unreal material created for the primitive + * @param association Type of association (layer, blend, global) being + * configured + * @param index Index of the layer or blend being configured (see + * association). Not relevant for global association. + */ + virtual void CustomizeGltfMaterial( + ICesiumLoadedTilePrimitive& TilePrim, + const CesiumGltf::Material& glTFmaterial, + const CesiumGltf::MaterialPBRMetallicRoughness& pbr, + UMaterialInstanceDynamic* pMaterial, + EMaterialParameterAssociation association, + int32 index); + + /** + * Called at the end of the static mesh component construction. + * @param TilePrim Loaded tile primitive being constructed + */ + virtual void + OnTileMeshPrimitiveConstructed(ICesiumLoadedTilePrimitive& TilePrim) = 0; + + /** + * Called at the end of all static mesh components' construction for a given + * tile. + * @param LoadedTile The tile that has just been loaded + */ + virtual void OnTileConstructed(ICesiumLoadedTile& LoadedTile) = 0; + + /** + * Called when changing the visibility of any UCesiumGltfComponent, ie usually + * several times per tile (when the tileset selection leads to showing or + * hiding a whole tile). + * @param LoadedTile The tile which visibility is being toggled + * @param visible New visibility flag being applied + */ + virtual void + OnVisibilityChanged(ICesiumLoadedTile& LoadedTile, bool visible) = 0; + + /** + * Called before a tile is destroyed (when it is unloaded, typically). + * @param LoadedTile The tile which is about to be unloaded + */ + virtual void BeforeTileDestruction(ICesiumLoadedTile& LoadedTile) = 0; +}; diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 976b80afb..94b01c5e4 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -14,37 +14,33 @@ class UStaticMeshComponent; UINTERFACE() -class UCesiumLoadedTileBase : public UInterface { +class UCesiumLoadedTile : public UInterface { GENERATED_BODY() }; -class ICesiumLoadedTileBase { - GENERATED_BODY() -public: - virtual Cesium3DTilesSelection::TileID const& GetTileID() const = 0; - virtual FCesiumModelMetadata const& GetModelMetadata() const = 0; -}; - -UINTERFACE() -class UCesiumLoadedTile : public UCesiumLoadedTileBase { - GENERATED_BODY() -}; -class ICesiumLoadedTile : public ICesiumLoadedTileBase { +class ICesiumLoadedTile { GENERATED_BODY() public: + /** Get the tile identifier: this is informational only, as there is no + * guarantee of unicity */ + virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; + virtual const FCesiumModelMetadata& GetModelMetadata() const = 0; virtual void SetRenderReady(bool bToggle) = 0; }; UINTERFACE() -class UCesiumLoadedTilePrimitive : public UCesiumLoadedTileBase { +class UCesiumLoadedTilePrimitive : public UInterface { GENERATED_BODY() }; -// Not merged with ICesiumPrimitive because this is Public whereas ICesiumPrimitive is Private -class ICesiumLoadedTilePrimitive : public ICesiumLoadedTileBase { +// Not merged with ICesiumPrimitive because this is Public whereas +// ICesiumPrimitive is Private +class ICesiumLoadedTilePrimitive { GENERATED_BODY() public: + virtual ICesiumLoadedTile& GetLoadedTile() = 0; virtual UStaticMeshComponent& GetMeshComponent() = 0; - virtual FCesiumPrimitiveFeatures const& GetPrimitiveFeatures() const = 0; - virtual FCesiumPrimitiveMetadata const& GetPrimitiveMetadata() const = 0; + virtual const FCesiumPrimitiveFeatures& GetPrimitiveFeatures() const = 0; + virtual const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const = 0; virtual const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const = 0; - virtual std::optional FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const = 0; + virtual std::optional + FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const = 0; }; diff --git a/Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h b/Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h deleted file mode 100644 index d55173971..000000000 --- a/Source/CesiumRuntime/Public/CesiumMeshBuildCallbacks.h +++ /dev/null @@ -1,104 +0,0 @@ -/*--------------------------------------------------------------------------------------+ -| -| $Source: CesiumMeshBuildCallbacks.h $ -| -| $Copyright: (c) 2024 Bentley Systems, Incorporated. All rights reserved. $ -| -+--------------------------------------------------------------------------------------*/ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -class UMaterialInstanceDynamic; -class UMaterialInterface; -enum EMaterialParameterAssociation : int; -class UStaticMeshComponent; -class USceneComponent; -struct FCesiumModelMetadata; -struct FCesiumPrimitiveFeatures; -class ICesiumTilePrimitiveData; - -namespace CesiumGltf { -struct MeshPrimitive; -struct Material; -struct MaterialPBRMetallicRoughness; -} // namespace CesiumGltf -namespace Cesium3DTilesSelection { -class Tile; -} - -/** Extension points for customizations requiring mesh and tile properties and - * lifecycle information. All methods are called from the game thread.*/ -class CESIUMRUNTIME_API CesiumMeshBuildCallbacks { -public: - CesiumMeshBuildCallbacks(); - virtual ~CesiumMeshBuildCallbacks(); - - /** - * Allows to override the base material from which loadPrimitiveGameThreadPart - *creates a dynamic material instance for the given primitive. The method can - *optionally create the material itself, if further customizations need to be - *done before returning the material, or can let the caller function do it - *based on InOut_pChosenBaseMaterial. - * \param InOut_pChosenBaseMaterial Input passes the default chosen base - *material. Can be modified so that the caller will create the material - *instance based on the custom base material (unless this method creates the - *material itself). - * \return Material instance created, or nullptr to let the caller create it. - */ - virtual UMaterialInstanceDynamic* CreateMaterial( - ICesiumLoadedTilePrimitive& TilePrim, - UMaterialInterface*& InOut_pChosenBaseMaterial, - UObject* InOuter, - FName const& Name) = 0; - - /** - * Customize the Unreal material instance, depending on the glTF material - * definition. - */ - virtual void CustomizeGltfMaterial( - const CesiumGltf::Material& glTFmaterial, - const CesiumGltf::MaterialPBRMetallicRoughness& pbr, - UMaterialInstanceDynamic* pMaterial, - EMaterialParameterAssociation association, - int32 index) const; - - /** - * Called at the end of the static mesh component construction. - */ - virtual void OnMeshConstructed( - ICesiumLoadedTile& LoadedTile, - ICesiumLoadedTilePrimitive& TilePrim) = 0; - - /** - * Called at the end of all static mesh components' construction for a given - * tile. - */ - virtual void - OnTileConstructed(const Cesium3DTilesSelection::TileID& TileID) = 0; - - /** - * Called when changing the visibility of any UCesiumGltfComponent, ie usually - * several times per tile (when the tileset selection leads to showing or - * hiding a whole tile). - */ - virtual void OnVisibilityChanged( - const Cesium3DTilesSelection::TileID& TileID, - bool visible) = 0; - - /** - * Called before a tile is destroyed (when it is unloaded, typically). - */ - virtual void - BeforeTileDestruction(const Cesium3DTilesSelection::TileID& TileID) = 0; - -private: - static TSharedPtr Singleton; -}; From 51d7b216ab1808ff8b7ca3e260174308f451ca38 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Mon, 19 May 2025 11:06:05 +0200 Subject: [PATCH 03/33] Fix missing condition on GetLifecycleEventReceiver() pointer --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 8c19b096c..6fd62d707 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3465,7 +3465,8 @@ UCesiumGltfComponent::CreateOffGameThread( } } } - pTilesetActor->GetLifecycleEventReceiver()->OnTileConstructed(*Gltf); + if (auto* Receiver = pTilesetActor->GetLifecycleEventReceiver()) + Receiver->OnTileConstructed(*Gltf); Gltf->SetVisibility(false, true); Gltf->SetCollisionEnabled(ECollisionEnabled::NoCollision); From e30313effc1c3c7d2f3a88b8b0fce0ec776c812a Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Mon, 19 May 2025 17:55:34 +0200 Subject: [PATCH 04/33] Reworked/simplified CreateMaterial/CustomizeMaterial --- .../Cesium3DTilesetLifecycleEventReceiver.cpp | 14 ++++----- .../Private/CesiumGltfComponent.cpp | 31 ++++++++----------- .../Cesium3DTilesetLifecycleEventReceiver.h | 20 +++++------- .../CesiumMaterialUserData.h | 0 4 files changed, 27 insertions(+), 38 deletions(-) rename Source/CesiumRuntime/{Private => Public}/CesiumMaterialUserData.h (100%) diff --git a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp index 0db9d0a78..5fd862e69 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp @@ -8,19 +8,17 @@ UMaterialInstanceDynamic* ICesium3DTilesetLifecycleEventReceiver::CreateMaterial( ICesiumLoadedTilePrimitive& TilePrim, UMaterialInterface* pBaseMaterial, - UObject* InOuter, const FName& Name) { // Default implementation: just create a new instance return UMaterialInstanceDynamic::Create( pBaseMaterial, - InOuter, + nullptr, Name); } -void ICesium3DTilesetLifecycleEventReceiver::CustomizeGltfMaterial( +void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial( ICesiumLoadedTilePrimitive& TilePrim, - const CesiumGltf::Material& /*glTFmaterial*/, - const CesiumGltf::MaterialPBRMetallicRoughness& /*pbr*/, - UMaterialInstanceDynamic* /*pMaterial*/, - EMaterialParameterAssociation /*association*/, - int32 /*index*/) {} + UMaterialInstanceDynamic&, + const UCesiumMaterialUserData*, + const CesiumGltf::Material&, + const CesiumGltf::MaterialPBRMetallicRoughness&) {} diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 6fd62d707..9deaca314 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -2463,8 +2463,7 @@ static void SetGltfParameterValues( const CesiumGltf::MaterialPBRMetallicRoughness& pbr, UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, - int32 index, - ICesium3DTilesetLifecycleEventReceiver* lifecycleEventReceiver) { + int32 index) { for (auto& textureCoordinateSet : loadResult.textureCoordinateParameters) { pMaterial->SetScalarParameterValueByInfo( FMaterialParameterInfo( @@ -2683,17 +2682,6 @@ static void SetGltfParameterValues( FMaterialParameterInfo("emissiveFactor", association, index), FVector(1.0f, 1.0f, 1.0f)); } - - // Extra material customizations - if (lifecycleEventReceiver) { - lifecycleEventReceiver->CustomizeGltfMaterial( - TilePrim, - material, - pbr, - pMaterial, - association, - index); - } } void SetWaterParameterValues( @@ -3171,7 +3159,6 @@ static void loadPrimitiveGameThreadPart( pMaterial = pLifecycleEventReceiver->CreateMaterial( *pCesiumPrimitive, pBaseMaterial, - nullptr, ImportedSlotName); if (pMaterial) { // pMaterial created above may not have used the suggested pBaseMaterial @@ -3196,8 +3183,7 @@ static void loadPrimitiveGameThreadPart( pbr, pMaterial, EMaterialParameterAssociation::GlobalParameter, - INDEX_NONE, - pLifecycleEventReceiver); + INDEX_NONE); SetWaterParameterValues( model, loadResult, @@ -3245,8 +3231,7 @@ static void loadPrimitiveGameThreadPart( pbr, pMaterial, EMaterialParameterAssociation::LayerParameter, - 0, - pLifecycleEventReceiver); + 0); // Initialize fade uniform to fully visible, in case LOD transitions // are off. @@ -3299,6 +3284,16 @@ static void loadPrimitiveGameThreadPart( metadataIndex); } } + + // Extra material customizations + if (pLifecycleEventReceiver) { + pLifecycleEventReceiver->CustomizeMaterial( + *pCesiumPrimitive, + *pMaterial, + pCesiumData, + material, + pbr); + } } primData.EncodedFeatures = std::move(loadResult.EncodedFeatures); diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index 2498e8f15..da6facdb3 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -14,6 +14,7 @@ enum EMaterialParameterAssociation : int; class ICesiumLoadedTile; class ICesiumLoadedTilePrimitive; +class UCesiumMaterialUserData; namespace CesiumGltf { struct Material; struct MaterialPBRMetallicRoughness; @@ -47,30 +48,25 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { virtual UMaterialInstanceDynamic* CreateMaterial( ICesiumLoadedTilePrimitive& TilePrim, UMaterialInterface* pDefaultBaseMaterial, - UObject* Outer, const FName& Name) = 0; /** * Customize the Unreal material instance, depending on the glTF material * definition. * @param TilePrim Loaded tile primitive to which the material applies + * @param Material Unreal material created for the primitive + * @param pCesiumData List of material layer names * @param glTFmaterial Parameters of the glTF material for the primitive - * @param glTFmaterial Parameters for this primitive's material defining the + * @param glTFmaterialPBR Parameters for this primitive's material defining the * metallic-roughness material model from Physically-Based Rendering (PBR) * methodology - * @param pMaterial Unreal material created for the primitive - * @param association Type of association (layer, blend, global) being - * configured - * @param index Index of the layer or blend being configured (see - * association). Not relevant for global association. */ - virtual void CustomizeGltfMaterial( + virtual void CustomizeMaterial( ICesiumLoadedTilePrimitive& TilePrim, + UMaterialInstanceDynamic& Material, + const UCesiumMaterialUserData* pCesiumData, const CesiumGltf::Material& glTFmaterial, - const CesiumGltf::MaterialPBRMetallicRoughness& pbr, - UMaterialInstanceDynamic* pMaterial, - EMaterialParameterAssociation association, - int32 index); + const CesiumGltf::MaterialPBRMetallicRoughness& glTFmaterialPBR); /** * Called at the end of the static mesh component construction. diff --git a/Source/CesiumRuntime/Private/CesiumMaterialUserData.h b/Source/CesiumRuntime/Public/CesiumMaterialUserData.h similarity index 100% rename from Source/CesiumRuntime/Private/CesiumMaterialUserData.h rename to Source/CesiumRuntime/Public/CesiumMaterialUserData.h From dd2bf547c334e1fa9176927f82b565dbacaf9976 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Wed, 28 May 2025 10:29:00 +0200 Subject: [PATCH 05/33] revert adding CPU access option from Tilesets --- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 8 ------- .../Private/CesiumGltfComponent.cpp | 15 +++---------- .../CesiumRuntime/Private/CreateGltfOptions.h | 6 ------ .../UnrealPrepareRendererResources.cpp | 2 -- Source/CesiumRuntime/Public/Cesium3DTileset.h | 21 ------------------- 5 files changed, 3 insertions(+), 49 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index ba8af4d50..585ebc2e8 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -445,14 +445,6 @@ void ACesium3DTileset::SetCesiumIonServer(UCesiumIonServer* Server) { } } -void ACesium3DTileset::SetAllowMeshBuffersCPUAccess( - bool InMeshBuffersCPUAccess) { - if (bAllowMeshBuffersCPUAccess != InMeshBuffersCPUAccess) { - this->bAllowMeshBuffersCPUAccess = InMeshBuffersCPUAccess; - this->DestroyTileset(); - } -} - void ACesium3DTileset::SetMaximumScreenSpaceError( double InMaximumScreenSpaceError) { if (MaximumScreenSpaceError != InMaximumScreenSpaceError) { diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 9deaca314..6c3e20f3b 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -1670,12 +1670,6 @@ static void loadPrimitive( computeTangentSpace(StaticMeshBuildVertices); } - // Note: there is already a representation of the geometry kept in CPU memory, - // which is the CesiumGltf::Model, so we should avoid keeping a second copy... - // (TODO: remove option) - bool bNeedsCPUAccess = options.pMeshOptions->pNodeOptions->pModelOptions - ->allowMeshBuffersCPUAccess; - { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::InitBuffers) @@ -1686,12 +1680,12 @@ static void loadPrimitive( true); LODResources.VertexBuffers.PositionVertexBuffer.Init( StaticMeshBuildVertices, - bNeedsCPUAccess); + false); FColorVertexBuffer& ColorVertexBuffer = LODResources.VertexBuffers.ColorVertexBuffer; if (hasVertexColors) { - ColorVertexBuffer.Init(StaticMeshBuildVertices, bNeedsCPUAccess); + ColorVertexBuffer.Init(StaticMeshBuildVertices, false); } uint32 numberOfTextureCoordinates = @@ -1704,7 +1698,7 @@ static void loadPrimitive( vertexBuffer.Init( StaticMeshBuildVertices.Num(), numberOfTextureCoordinates, - bNeedsCPUAccess); + false); // Manually copy the vertices into the buffer. We do this because UE 5.3 // and 5.4 have a bug where the overload of `FStaticMeshVertexBuffer::Init` @@ -1751,9 +1745,6 @@ static void loadPrimitive( { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::SetIndices) - if (bNeedsCPUAccess) { - LODResources.IndexBuffer.TrySetAllowCPUAccess(true); - } LODResources.IndexBuffer.SetIndices( indices, StaticMeshBuildVertices.Num() >= std::numeric_limits::max() diff --git a/Source/CesiumRuntime/Private/CreateGltfOptions.h b/Source/CesiumRuntime/Private/CreateGltfOptions.h index e0a5c5094..ce8c7a5ee 100644 --- a/Source/CesiumRuntime/Private/CreateGltfOptions.h +++ b/Source/CesiumRuntime/Private/CreateGltfOptions.h @@ -52,11 +52,6 @@ struct CreateModelOptions { */ bool ignoreKhrMaterialsUnlit = false; - /** Whether to configure the Unreal mesh buffers to allow access from CPU. If - * this is false, the buffers can be freed from CPU memory at any time after - * they have been moved to GPU memory. */ - bool allowMeshBuffersCPUAccess = false; - Cesium3DTilesSelection::TileLoadResult tileLoadResult; public: @@ -72,7 +67,6 @@ struct CreateModelOptions { alwaysIncludeTangents(other.alwaysIncludeTangents), createPhysicsMeshes(other.createPhysicsMeshes), ignoreKhrMaterialsUnlit(other.ignoreKhrMaterialsUnlit), - allowMeshBuffersCPUAccess(other.allowMeshBuffersCPUAccess), tileLoadResult(std::move(other.tileLoadResult)) { pModel = std::get_if(&this->tileLoadResult.contentKind); } diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp index 63379040d..b8bfb1d4d 100644 --- a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -35,8 +35,6 @@ UnrealPrepareRendererResources::prepareInLoadThread( options.alwaysIncludeTangents = this->_pActor->GetAlwaysIncludeTangents(); options.createPhysicsMeshes = this->_pActor->GetCreatePhysicsMeshes(); - options.allowMeshBuffersCPUAccess = - this->_pActor->GetAllowMeshBuffersCPUAccess(); options.ignoreKhrMaterialsUnlit = this->_pActor->GetIgnoreKhrMaterialsUnlit(); diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index a07063618..c93eeed0b 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -342,19 +342,6 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { UFUNCTION(BlueprintCallable, Category = "Cesium") void InvalidateResolvedCameraManager(); - /** - * Whether to configure the Unreal mesh buffers to allow access from CPU. If - * this is false, the buffers can be freed from CPU memory at any time after - * they have been moved to GPU memory: set to true if you need to access these - * buffers for your game logic. - */ - UPROPERTY( - EditAnywhere, - BlueprintGetter = GetAllowMeshBuffersCPUAccess, - BlueprintSetter = SetAllowMeshBuffersCPUAccess, - Category = "Cesium") - bool bAllowMeshBuffersCPUAccess = false; - /** * The maximum number of pixels of error when rendering this tileset. * @@ -1082,14 +1069,6 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { UFUNCTION(BlueprintSetter, Category = "Cesium") void SetMaximumScreenSpaceError(double InMaximumScreenSpaceError); - UFUNCTION(BlueprintGetter, Category = "Cesium") - bool GetAllowMeshBuffersCPUAccess() const { - return bAllowMeshBuffersCPUAccess; - } - - UFUNCTION(BlueprintSetter, Category = "Cesium") - void SetAllowMeshBuffersCPUAccess(bool bMeshBuffersCPUAccess); - UFUNCTION(BlueprintGetter, Category = "Cesium|Tile Culling|Experimental") bool GetEnableOcclusionCulling() const; From 65efbd26484781803855ca0ad9e1e900946258ff Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Wed, 28 May 2025 11:41:54 +0200 Subject: [PATCH 06/33] Remove CPU access option mention from CHANGES.md --- CHANGES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 45a764643..5ff3a9c87 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,7 +21,6 @@ - Added a Cesium -> Geocoder -> Geocode Blueprint function, making it easy to query the Cesium ion geocoder. - Added `UCesiumMetadataPickingBlueprintLibrary::FindPropertyTableProperty` to search for a `FCesiumPropertyTableProperty` by name on a given `UPrimitiveComponent`. -- Added a property `bAllowMeshBuffersCPUAccess` to `ACesium3DTileset` actors to keep the buffers of Unreal meshes created by the tileset in CPU memory, in order to have access to them in-game. Defaults to false. - Added the class `CesiumMeshBuildCallbacks`: when an implementation is registered on a tileset (with `ACesium3DTileset::SetMeshBuildCallbacks`), its functions will be called at various points in a tile's lifecycle, like when a mesh component is created, when a material is instanced, when the tile changes visibility, when it is unloaded, etc. ##### Fixes :wrench: From 5d357f500f1a3e7f3e6e4d97eb295a7e12b3c378 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Wed, 11 Jun 2025 12:06:12 +0200 Subject: [PATCH 07/33] AdvViz: add GetVertexPositionScaleFactor to UCesiumLoadedTile to make sense of glTF vertices --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 11 +++++++++++ Source/CesiumRuntime/Private/CesiumGltfComponent.h | 1 + Source/CesiumRuntime/Public/CesiumLoadedTile.h | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 7bde8947f..b77fed84f 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -1558,6 +1558,8 @@ static void loadPrimitive( positionBuffer.Init(numVertices, false); { + // Note: scaling from glTF vertices to Unreal's must match + // UCesiumGltfComponent::GetGltfToUnrealLocalVertexPositionScaleFactor if (duplicateVertices) { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::CopyDuplicatedPositions) for (uint32 i = 0; i < numVertices; ++i) { @@ -3601,6 +3603,15 @@ const Cesium3DTilesSelection::TileID& UCesiumGltfComponent::GetTileID() const { return pTile->getTileID(); } +FVector +UCesiumGltfComponent::GetGltfToUnrealLocalVertexPositionScaleFactor() const { + // Note: replicates logic from (static) loadPrimitive + return FVector( + CesiumPrimitiveData::positionScaleFactor, + -CesiumPrimitiveData::positionScaleFactor, + CesiumPrimitiveData::positionScaleFactor); +} + void UCesiumGltfComponent::SetRenderReady(bool bToggle) { if (pTile) { pTile->setRenderEngineReadiness(bToggle); diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index 07a5d205a..6b2a27a21 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -140,6 +140,7 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { // from ICesiumLoadedTile const FCesiumModelMetadata& GetModelMetadata() const override; const Cesium3DTilesSelection::TileID& GetTileID() const override; + FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const override; void SetRenderReady(bool bToggle) override; void UpdateFade(float fadePercentage, bool fadingIn); diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 94b01c5e4..1a52bca05 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -7,6 +7,7 @@ #include "CesiumPrimitiveFeatures.h" #include "CesiumPrimitiveMetadata.h" +#include "Math/Vector.h" #include "UObject/ObjectMacros.h" #include "CesiumLoadedTile.generated.h" @@ -23,6 +24,11 @@ class ICesiumLoadedTile { /** Get the tile identifier: this is informational only, as there is no * guarantee of unicity */ virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; + /** Scaling factor to be applied (component-wise multiplication) to glTF + * vertices of this tile's models to obtain the values represented in their + * matching mesh component (see @{link + * UCesiumLoadedTilePrimitive::GetMeshComponent). */ + virtual FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const = 0; virtual const FCesiumModelMetadata& GetModelMetadata() const = 0; virtual void SetRenderReady(bool bToggle) = 0; }; From 380fa1349d7c6ab60083ca5275258a39b30691a3 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Tue, 17 Jun 2025 09:09:45 +0200 Subject: [PATCH 08/33] CesiumMetadataValueAccess => FCesiumMetadataValueAccess --- .../Private/CesiumMetadataValue.cpp | 2 +- .../Tests/CesiumMetadataValue.spec.cpp | 37 +++++++++++++------ .../Public/CesiumMetadataValue.h | 4 +- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp b/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp index 59b7b315b..d8e5617ac 100644 --- a/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp +++ b/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp @@ -334,7 +334,7 @@ TMap UCesiumMetadataValueBlueprintLibrary::GetValuesAsStrings( return strings; } -uint64 CesiumMetadataValueAccess::GetUnsignedInteger64( +uint64 FCesiumMetadataValueAccess::GetUnsignedInteger64( const FCesiumMetadataValue& Value, uint64 DefaultValue) { return swl::visit( diff --git a/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp b/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp index 701b88a8d..6a21f65c9 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp +++ b/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp @@ -1274,25 +1274,34 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(std::numeric_limits::max() - 1); TestEqual( "uint64_t", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), std::numeric_limits::max() - 1); - value = FCesiumMetadataValue(std::numeric_limits::max() - 1); + value = + FCesiumMetadataValue(std::numeric_limits::max() - 1); TestEqual( "int64_t", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), static_cast(std::numeric_limits::max() - 1)); value = FCesiumMetadataValue(static_cast(12345)); TestEqual( "smaller signed integer", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), static_cast(12345)); value = FCesiumMetadataValue(static_cast(255)); TestEqual( "smaller unsigned integer", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), static_cast(255)); }); @@ -1300,7 +1309,9 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(true); TestEqual( "value", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), static_cast(1)); }); @@ -1308,7 +1319,9 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(1234.56f); TestEqual( "float", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), static_cast(1234)); }); @@ -1316,7 +1329,9 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(std::string_view("1234")); TestEqual( "value", - CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), + FCesiumMetadataValueAccess::GetUnsignedInteger64( + value, + defaultValue), static_cast(1234)); }); @@ -1325,7 +1340,7 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(-5); TestEqual( "negative integer", - CesiumMetadataValueAccess::GetUnsignedInteger64( + FCesiumMetadataValueAccess::GetUnsignedInteger64( value, defaultValue), defaultValue); @@ -1333,7 +1348,7 @@ void FCesiumMetadataValueSpec::Define() { value = FCesiumMetadataValue(-59.62f); TestEqual( "negative floating-point number", - CesiumMetadataValueAccess::GetUnsignedInteger64( + FCesiumMetadataValueAccess::GetUnsignedInteger64( value, defaultValue), defaultValue); @@ -1341,7 +1356,7 @@ void FCesiumMetadataValueSpec::Define() { value = FCesiumMetadataValue(std::numeric_limits::max()); TestEqual( "positive floating-point number", - CesiumMetadataValueAccess::GetUnsignedInteger64( + FCesiumMetadataValueAccess::GetUnsignedInteger64( value, defaultValue), defaultValue); diff --git a/Source/CesiumRuntime/Public/CesiumMetadataValue.h b/Source/CesiumRuntime/Public/CesiumMetadataValue.h index 3789be844..9ece3030a 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataValue.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataValue.h @@ -265,7 +265,7 @@ struct CESIUMRUNTIME_API FCesiumMetadataValue { TSharedPtr _pEnumDefinition; friend class UCesiumMetadataValueBlueprintLibrary; - friend class CesiumMetadataValueAccess; + friend class FCesiumMetadataValueAccess; }; UCLASS() @@ -867,7 +867,7 @@ class CESIUMRUNTIME_API UCesiumMetadataValueBlueprintLibrary * These should be moved to UCesiumMetadataValueBlueprintLibrary if those types * become compatible with Blueprints in the future. */ -class CESIUMRUNTIME_API CesiumMetadataValueAccess { +class CESIUMRUNTIME_API FCesiumMetadataValueAccess { public: /** From 335d61202cf4acdd0b0c7784b1a755b294ab17f5 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Tue, 17 Jun 2025 09:12:59 +0200 Subject: [PATCH 09/33] missing fwd decl --- .../CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h b/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h index d35dbc798..1788c5eca 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h @@ -11,6 +11,7 @@ struct FHitResult; struct FCesiumPrimitiveFeatures; struct FCesiumModelMetadata; +struct FCesiumPropertyTableProperty; UCLASS() class CESIUMRUNTIME_API UCesiumMetadataPickingBlueprintLibrary From d58decc67474552d4444e140a989a6419233d3f5 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Tue, 17 Jun 2025 13:22:45 +0200 Subject: [PATCH 10/33] Hide implementation detail * give access to Tileset actor --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 11 +++++++---- Source/CesiumRuntime/Private/CesiumGltfComponent.h | 1 + Source/CesiumRuntime/Public/CesiumLoadedTile.h | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index b77fed84f..42bf1ec4f 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3197,8 +3197,8 @@ static void loadPrimitiveGameThreadPart( pBaseMaterial, ImportedSlotName); if (pMaterialForGltfPrimitive) { - // pMaterialForGltfPrimitive created above may not have used the suggested - // pBaseMaterial passed as input + // pMaterialForGltfPrimitive created above may not have used the + // suggested pBaseMaterial passed as input pBaseMaterial = pMaterialForGltfPrimitive->Parent.Get(); // may have changed but we don't need it from now on: pUserDesignatedMaterialAsDynamic = nullptr; @@ -3559,8 +3559,7 @@ UCesiumGltfComponent::CreateOffGameThread( void UCesiumGltfComponent::OnVisibilityChanged() { USceneComponent::OnVisibilityChanged(); - auto* pLifecycleEventReceiver = - Cast(GetOuter())->GetLifecycleEventReceiver(); + auto* pLifecycleEventReceiver = GetTilesetActor().GetLifecycleEventReceiver(); if (pLifecycleEventReceiver) pLifecycleEventReceiver->OnVisibilityChanged(*this, GetVisibleFlag()); } @@ -3603,6 +3602,10 @@ const Cesium3DTilesSelection::TileID& UCesiumGltfComponent::GetTileID() const { return pTile->getTileID(); } +ACesium3DTileset& UCesiumGltfComponent::GetTilesetActor() { + return *Cast(GetOuter()); +} + FVector UCesiumGltfComponent::GetGltfToUnrealLocalVertexPositionScaleFactor() const { // Note: replicates logic from (static) loadPrimitive diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index 6b2a27a21..437b9318d 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -140,6 +140,7 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { // from ICesiumLoadedTile const FCesiumModelMetadata& GetModelMetadata() const override; const Cesium3DTilesSelection::TileID& GetTileID() const override; + ACesium3DTileset& GetTilesetActor() override; FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const override; void SetRenderReady(bool bToggle) override; diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 1a52bca05..71b929e5f 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -12,6 +12,7 @@ #include "CesiumLoadedTile.generated.h" +class ACesium3DTileset; class UStaticMeshComponent; UINTERFACE() @@ -25,10 +26,11 @@ class ICesiumLoadedTile { * guarantee of unicity */ virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; /** Scaling factor to be applied (component-wise multiplication) to glTF - * vertices of this tile's models to obtain the values represented in their + * vertices of this tile's model to obtain the values represented in their * matching mesh component (see @{link * UCesiumLoadedTilePrimitive::GetMeshComponent). */ virtual FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const = 0; + virtual ACesium3DTileset& GetTilesetActor() = 0; virtual const FCesiumModelMetadata& GetModelMetadata() const = 0; virtual void SetRenderReady(bool bToggle) = 0; }; From e4336acf6bca779248ea91735896ea037d0f4591 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Tue, 22 Jul 2025 15:26:48 +0200 Subject: [PATCH 11/33] Revert addition of tile render-readiness concept --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 6 ------ Source/CesiumRuntime/Private/CesiumGltfComponent.h | 1 - Source/CesiumRuntime/Public/CesiumLoadedTile.h | 1 - extern/cesium-native | 2 +- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 42bf1ec4f..9e5b41eba 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3615,12 +3615,6 @@ UCesiumGltfComponent::GetGltfToUnrealLocalVertexPositionScaleFactor() const { CesiumPrimitiveData::positionScaleFactor); } -void UCesiumGltfComponent::SetRenderReady(bool bToggle) { - if (pTile) { - pTile->setRenderEngineReadiness(bToggle); - } -} - void UCesiumGltfComponent::UpdateTransformFromCesium( const glm::dmat4& cesiumToUnrealTransform) { for (USceneComponent* pSceneComponent : this->GetAttachChildren()) { diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index 437b9318d..cbd984ab2 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -142,7 +142,6 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { const Cesium3DTilesSelection::TileID& GetTileID() const override; ACesium3DTileset& GetTilesetActor() override; FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const override; - void SetRenderReady(bool bToggle) override; void UpdateFade(float fadePercentage, bool fadingIn); diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 71b929e5f..2f7c99636 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -32,7 +32,6 @@ class ICesiumLoadedTile { virtual FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const = 0; virtual ACesium3DTileset& GetTilesetActor() = 0; virtual const FCesiumModelMetadata& GetModelMetadata() const = 0; - virtual void SetRenderReady(bool bToggle) = 0; }; UINTERFACE() diff --git a/extern/cesium-native b/extern/cesium-native index 6bee55bec..020603bdd 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit 6bee55bec2cb782f1193ca2fa1c74c0073a13a23 +Subproject commit 020603bdd4254bcdf333b08209def90468629917 From c33861f20a6bb71b546f47522f6276e84ec77842 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Tue, 22 Jul 2025 15:32:24 +0200 Subject: [PATCH 12/33] Update CHANGES.md --- CHANGES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d258e2771..3c2c3edaa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ### ? - ? +##### Additions :tada: + +- Added the interface `ICesium3DTilesetLifecycleEventReceiver`: when an implementation is registered on a tileset (with `ACesium3DTileset::SetLifecycleEventReceiver`), its functions will be called at various points in a tile's lifecycle, like when a mesh component is created, when a material is instanced, when the tile changes visibility, when it is unloaded, etc. + ##### Fixes :wrench: - Fixed error messages in the Unreal log about uninitialized fields in `FCesiumGeocoderServiceAttribution` and `FCesiumGeocoderServiceFeature`. @@ -46,7 +50,6 @@ In addition to the above, this release updates [cesium-native](https://github.co - Added a Cesium -> Geocoder -> Geocode Blueprint function, making it easy to query the Cesium ion geocoder. - Added `UCesiumMetadataPickingBlueprintLibrary::FindPropertyTableProperty` to search for a `FCesiumPropertyTableProperty` by name on a given `UPrimitiveComponent`. -- Added the class `CesiumMeshBuildCallbacks`: when an implementation is registered on a tileset (with `ACesium3DTileset::SetMeshBuildCallbacks`), its functions will be called at various points in a tile's lifecycle, like when a mesh component is created, when a material is instanced, when the tile changes visibility, when it is unloaded, etc. ##### Fixes :wrench: From f047b249d8d98491ec5cb697541177cc8fad2130 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 15:25:42 +0200 Subject: [PATCH 13/33] _lifecycleEventReceive => _pLifecycleEventReceive, make it visible to GC Which was not possible with a TObjectPtr: tried a TScriptInterface, but decided for a UObject after reading about caveats: see comments over UCesium3DTilesetLifecycleEventReceiver. Also flagged UCesium3DTilesetLifecycleEventReceiver with 'CannotImplementInterfaceInBlueprint' --- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 15 +++++++++++--- Source/CesiumRuntime/Public/Cesium3DTileset.h | 20 ++++++++++++------- .../Cesium3DTilesetLifecycleEventReceiver.h | 11 +++++++++- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 6b459f814..5facaf8d9 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -11,6 +11,7 @@ #include "Cesium3DTilesSelection/TilesetOptions.h" #include "Cesium3DTilesSelection/TilesetSharedAssetSystem.h" #include "Cesium3DTilesetLoadFailureDetails.h" +#include "Cesium3DTilesetLifecycleEventReceiver.h" #include "Cesium3DTilesetRoot.h" #include "CesiumActors.h" #include "CesiumAsync/SharedAssetDepot.h" @@ -2329,7 +2330,15 @@ void ACesium3DTileset::RuntimeSettingsChanged( } #endif -void ACesium3DTileset::SetLifecycleEventReceiver( - ICesium3DTilesetLifecycleEventReceiver* InEventReceiver) { - this->_lifecycleEventReceiver = InEventReceiver; +ICesium3DTilesetLifecycleEventReceiver* +ACesium3DTileset::GetLifecycleEventReceiver() { + return Cast( + this->_pLifecycleEventReceiver); +} + +void ACesium3DTileset::SetLifecycleEventReceiver(UObject* InEventReceiver) { + if (UKismetSystemLibrary::DoesImplementInterface( + InEventReceiver, + UCesium3DTilesetLifecycleEventReceiver::StaticClass())) + this->_pLifecycleEventReceiver = InEventReceiver; } diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index c93eeed0b..ad88ea6f0 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -1261,15 +1261,14 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { /** Gets the optional receiver of events related to tile components' lifecycle */ - ICesium3DTilesetLifecycleEventReceiver* GetLifecycleEventReceiver() { - return this->_lifecycleEventReceiver; - } + ICesium3DTilesetLifecycleEventReceiver* GetLifecycleEventReceiver(); /** Sets a receiver of events related to tile components' lifecycle, * like tile primitive and material creation, tile finishing its loading cycle - * or about to unload, etc. */ - void SetLifecycleEventReceiver( - ICesium3DTilesetLifecycleEventReceiver* InEventReceiver); + * or about to unload, etc. It must implement + * {@link ICesium3DTilesetLifecycleEventReceiver}, otherwise it will be as if + * nullptr were passed. */ + void SetLifecycleEventReceiver(UObject* InEventReceiver); private: /** @@ -1385,7 +1384,14 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { int32 _tilesetsBeingDestroyed; - ICesium3DTilesetLifecycleEventReceiver* _lifecycleEventReceiver; + // Make this visible to the garbage collector, but don't save/load/copy it. + // Use UObject instead of TScriptInterface as suggested by + // https://www.stevestreeting.com/2020/11/02/ue4-c-interfaces-hints-n-tips/, + // even though this cannot be implemented through Blueprints for the moment + // (see comment over UCesium3DTilesetLifecycleEventReceiver for instructions), + // it's best being prepared for the future. + UPROPERTY(Transient, DuplicateTransient, TextExportTransient) + UObject* _pLifecycleEventReceiver; friend class UnrealPrepareRendererResources; friend class UCesiumGltfPointsComponent; diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index da6facdb3..bf81d761e 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -20,7 +20,16 @@ struct Material; struct MaterialPBRMetallicRoughness; } // namespace CesiumGltf -UINTERFACE() +// Note: to allow implementation in Blueprints: +// 1. remove this 'meta' flag, and make the interface methods below +// compatible with a Blueprint implementation, +// 2. remove the Cast in +// ACesium3DTileset::GetLifecycleEventReceiver, as it would return nullptr for a +// BP implementation, and return the UObject pointer instead, +// 3. use ICesium3DTilesetLifecycleEventReceiver::Execute_DoStuff wrappers +// instead of DoStuff methods everywhere the event receiver is used in the +// plugin's C++ code. +UINTERFACE(meta = (CannotImplementInterfaceInBlueprint)) class UCesium3DTilesetLifecycleEventReceiver : public UInterface { GENERATED_BODY() }; From 1293e317ab2ffebd21c3bf99122562f3c9b61b4b Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 15:26:28 +0200 Subject: [PATCH 14/33] Methods are no longer pure virtual, which is more user friendly --- .../Cesium3DTilesetLifecycleEventReceiver.cpp | 18 ++++++++++++++---- .../Cesium3DTilesetLifecycleEventReceiver.h | 10 +++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp index 5fd862e69..ebf02e3df 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp @@ -10,10 +10,7 @@ ICesium3DTilesetLifecycleEventReceiver::CreateMaterial( UMaterialInterface* pBaseMaterial, const FName& Name) { // Default implementation: just create a new instance - return UMaterialInstanceDynamic::Create( - pBaseMaterial, - nullptr, - Name); + return UMaterialInstanceDynamic::Create(pBaseMaterial, nullptr, Name); } void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial( @@ -22,3 +19,16 @@ void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial( const UCesiumMaterialUserData*, const CesiumGltf::Material&, const CesiumGltf::MaterialPBRMetallicRoughness&) {} + +void ICesium3DTilesetLifecycleEventReceiver::OnTileMeshPrimitiveConstructed( + ICesiumLoadedTilePrimitive& TilePrim) {} + +void ICesium3DTilesetLifecycleEventReceiver::OnTileConstructed( + ICesiumLoadedTile& LoadedTile) {} + +void ICesium3DTilesetLifecycleEventReceiver::OnVisibilityChanged( + ICesiumLoadedTile& LoadedTile, + bool visible) {} + +void ICesium3DTilesetLifecycleEventReceiver::BeforeTileDestruction( + ICesiumLoadedTile& LoadedTile) {} diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index bf81d761e..55f990cc1 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -57,7 +57,7 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { virtual UMaterialInstanceDynamic* CreateMaterial( ICesiumLoadedTilePrimitive& TilePrim, UMaterialInterface* pDefaultBaseMaterial, - const FName& Name) = 0; + const FName& Name); /** * Customize the Unreal material instance, depending on the glTF material @@ -82,14 +82,14 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { * @param TilePrim Loaded tile primitive being constructed */ virtual void - OnTileMeshPrimitiveConstructed(ICesiumLoadedTilePrimitive& TilePrim) = 0; + OnTileMeshPrimitiveConstructed(ICesiumLoadedTilePrimitive& TilePrim); /** * Called at the end of all static mesh components' construction for a given * tile. * @param LoadedTile The tile that has just been loaded */ - virtual void OnTileConstructed(ICesiumLoadedTile& LoadedTile) = 0; + virtual void OnTileConstructed(ICesiumLoadedTile& LoadedTile); /** * Called when changing the visibility of any UCesiumGltfComponent, ie usually @@ -99,11 +99,11 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { * @param visible New visibility flag being applied */ virtual void - OnVisibilityChanged(ICesiumLoadedTile& LoadedTile, bool visible) = 0; + OnVisibilityChanged(ICesiumLoadedTile& LoadedTile, bool visible); /** * Called before a tile is destroyed (when it is unloaded, typically). * @param LoadedTile The tile which is about to be unloaded */ - virtual void BeforeTileDestruction(ICesiumLoadedTile& LoadedTile) = 0; + virtual void BeforeTileDestruction(ICesiumLoadedTile& LoadedTile); }; From e16a06173e92aa0fd679eb55a4f453419ae8261a Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 15:26:48 +0200 Subject: [PATCH 15/33] language --- Source/CesiumRuntime/Public/CesiumLoadedTile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 2f7c99636..4a8c1f27d 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -23,7 +23,7 @@ class ICesiumLoadedTile { GENERATED_BODY() public: /** Get the tile identifier: this is informational only, as there is no - * guarantee of unicity */ + * guarantee of uniqueness */ virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; /** Scaling factor to be applied (component-wise multiplication) to glTF * vertices of this tile's model to obtain the values represented in their From 1adf4644808d1c575372a04c4314bc68bf06f8a3 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 15:40:20 +0200 Subject: [PATCH 16/33] Revert "CesiumMetadataValueAccess => FCesiumMetadataValueAccess" This reverts commit 380fa1349d7c6ab60083ca5275258a39b30691a3. I was supposed to remove the F from our version, not add it to the upstream... ;^^ --- .../Private/CesiumMetadataValue.cpp | 2 +- .../Tests/CesiumMetadataValue.spec.cpp | 37 ++++++------------- .../Public/CesiumMetadataValue.h | 4 +- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp b/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp index d8e5617ac..59b7b315b 100644 --- a/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp +++ b/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp @@ -334,7 +334,7 @@ TMap UCesiumMetadataValueBlueprintLibrary::GetValuesAsStrings( return strings; } -uint64 FCesiumMetadataValueAccess::GetUnsignedInteger64( +uint64 CesiumMetadataValueAccess::GetUnsignedInteger64( const FCesiumMetadataValue& Value, uint64 DefaultValue) { return swl::visit( diff --git a/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp b/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp index 6a21f65c9..701b88a8d 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp +++ b/Source/CesiumRuntime/Private/Tests/CesiumMetadataValue.spec.cpp @@ -1274,34 +1274,25 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(std::numeric_limits::max() - 1); TestEqual( "uint64_t", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), std::numeric_limits::max() - 1); - value = - FCesiumMetadataValue(std::numeric_limits::max() - 1); + value = FCesiumMetadataValue(std::numeric_limits::max() - 1); TestEqual( "int64_t", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), static_cast(std::numeric_limits::max() - 1)); value = FCesiumMetadataValue(static_cast(12345)); TestEqual( "smaller signed integer", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), static_cast(12345)); value = FCesiumMetadataValue(static_cast(255)); TestEqual( "smaller unsigned integer", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), static_cast(255)); }); @@ -1309,9 +1300,7 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(true); TestEqual( "value", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), static_cast(1)); }); @@ -1319,9 +1308,7 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(1234.56f); TestEqual( "float", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), static_cast(1234)); }); @@ -1329,9 +1316,7 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(std::string_view("1234")); TestEqual( "value", - FCesiumMetadataValueAccess::GetUnsignedInteger64( - value, - defaultValue), + CesiumMetadataValueAccess::GetUnsignedInteger64(value, defaultValue), static_cast(1234)); }); @@ -1340,7 +1325,7 @@ void FCesiumMetadataValueSpec::Define() { FCesiumMetadataValue value(-5); TestEqual( "negative integer", - FCesiumMetadataValueAccess::GetUnsignedInteger64( + CesiumMetadataValueAccess::GetUnsignedInteger64( value, defaultValue), defaultValue); @@ -1348,7 +1333,7 @@ void FCesiumMetadataValueSpec::Define() { value = FCesiumMetadataValue(-59.62f); TestEqual( "negative floating-point number", - FCesiumMetadataValueAccess::GetUnsignedInteger64( + CesiumMetadataValueAccess::GetUnsignedInteger64( value, defaultValue), defaultValue); @@ -1356,7 +1341,7 @@ void FCesiumMetadataValueSpec::Define() { value = FCesiumMetadataValue(std::numeric_limits::max()); TestEqual( "positive floating-point number", - FCesiumMetadataValueAccess::GetUnsignedInteger64( + CesiumMetadataValueAccess::GetUnsignedInteger64( value, defaultValue), defaultValue); diff --git a/Source/CesiumRuntime/Public/CesiumMetadataValue.h b/Source/CesiumRuntime/Public/CesiumMetadataValue.h index 9ece3030a..3789be844 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataValue.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataValue.h @@ -265,7 +265,7 @@ struct CESIUMRUNTIME_API FCesiumMetadataValue { TSharedPtr _pEnumDefinition; friend class UCesiumMetadataValueBlueprintLibrary; - friend class FCesiumMetadataValueAccess; + friend class CesiumMetadataValueAccess; }; UCLASS() @@ -867,7 +867,7 @@ class CESIUMRUNTIME_API UCesiumMetadataValueBlueprintLibrary * These should be moved to UCesiumMetadataValueBlueprintLibrary if those types * become compatible with Blueprints in the future. */ -class CESIUMRUNTIME_API FCesiumMetadataValueAccess { +class CESIUMRUNTIME_API CesiumMetadataValueAccess { public: /** From f2fd3a0319a3635623db8297b12b1ab9bde6d9a0 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 15:54:48 +0200 Subject: [PATCH 17/33] Semantics and comments' rewrite by K.Ring --- .../Cesium3DTilesetLifecycleEventReceiver.cpp | 34 ++++---- .../Private/CesiumGltfComponent.cpp | 6 +- .../UnrealPrepareRendererResources.cpp | 2 +- .../Cesium3DTilesetLifecycleEventReceiver.h | 82 ++++++++++--------- 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp index ebf02e3df..7786b50ca 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp @@ -6,29 +6,29 @@ UMaterialInstanceDynamic* ICesium3DTilesetLifecycleEventReceiver::CreateMaterial( - ICesiumLoadedTilePrimitive& TilePrim, - UMaterialInterface* pBaseMaterial, + ICesiumLoadedTilePrimitive& TilePrimitive, + UMaterialInterface* DefaultBaseMaterial, const FName& Name) { // Default implementation: just create a new instance - return UMaterialInstanceDynamic::Create(pBaseMaterial, nullptr, Name); + return UMaterialInstanceDynamic::Create(DefaultBaseMaterial, nullptr, Name); } void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial( - ICesiumLoadedTilePrimitive& TilePrim, - UMaterialInstanceDynamic&, - const UCesiumMaterialUserData*, - const CesiumGltf::Material&, - const CesiumGltf::MaterialPBRMetallicRoughness&) {} + ICesiumLoadedTilePrimitive& TilePrimitive, + UMaterialInstanceDynamic& Material, + const UCesiumMaterialUserData* CesiumData, + const CesiumGltf::Material& GlTFmaterial, + const CesiumGltf::MaterialPBRMetallicRoughness& GlTFmaterialPBR) {} -void ICesium3DTilesetLifecycleEventReceiver::OnTileMeshPrimitiveConstructed( - ICesiumLoadedTilePrimitive& TilePrim) {} +void ICesium3DTilesetLifecycleEventReceiver::OnTileMeshPrimitiveLoaded( + ICesiumLoadedTilePrimitive& TilePrimitive) {} -void ICesium3DTilesetLifecycleEventReceiver::OnTileConstructed( - ICesiumLoadedTile& LoadedTile) {} +void ICesium3DTilesetLifecycleEventReceiver::OnTileLoaded( + ICesiumLoadedTile& Tile) {} -void ICesium3DTilesetLifecycleEventReceiver::OnVisibilityChanged( - ICesiumLoadedTile& LoadedTile, - bool visible) {} +void ICesium3DTilesetLifecycleEventReceiver::OnTileVisibilityChanged( + ICesiumLoadedTile& Tile, + bool bVisible) {} -void ICesium3DTilesetLifecycleEventReceiver::BeforeTileDestruction( - ICesiumLoadedTile& LoadedTile) {} +void ICesium3DTilesetLifecycleEventReceiver::OnTileUnloading( + ICesiumLoadedTile& Tile) {} diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index abbfcc321..48e78b9d0 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3454,7 +3454,7 @@ static void loadPrimitiveGameThreadPart( // Call the observer callback (if any) once all is done if (pLifecycleEventReceiver) { - pLifecycleEventReceiver->OnTileMeshPrimitiveConstructed(*pCesiumPrimitive); + pLifecycleEventReceiver->OnTileMeshPrimitiveLoaded(*pCesiumPrimitive); } } @@ -3541,7 +3541,7 @@ UCesiumGltfComponent::CreateOffGameThread( } } if (auto* Receiver = pTilesetActor->GetLifecycleEventReceiver()) - Receiver->OnTileConstructed(*Gltf); + Receiver->OnTileLoaded(*Gltf); Gltf->SetVisibility(false, true); Gltf->SetCollisionEnabled(ECollisionEnabled::NoCollision); @@ -3552,7 +3552,7 @@ void UCesiumGltfComponent::OnVisibilityChanged() { USceneComponent::OnVisibilityChanged(); auto* pLifecycleEventReceiver = GetTilesetActor().GetLifecycleEventReceiver(); if (pLifecycleEventReceiver) - pLifecycleEventReceiver->OnVisibilityChanged(*this, GetVisibleFlag()); + pLifecycleEventReceiver->OnTileVisibilityChanged(*this, GetVisibleFlag()); } UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() { diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp index b8bfb1d4d..07cb4fb92 100644 --- a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -104,7 +104,7 @@ void UnrealPrepareRendererResources::free( UCesiumGltfComponent* pGltf = reinterpret_cast(pMainThreadResult); if (auto* Receiver = this->_pActor->GetLifecycleEventReceiver()) { - Receiver->BeforeTileDestruction(*pGltf); + Receiver->OnTileUnloading(*pGltf); } CesiumLifetime::destroyComponentRecursively(pGltf); } diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index 55f990cc1..c540c8ebf 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -39,71 +39,75 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { GENERATED_BODY() public: /** - * Allows to override the base material from which the given tile primitive's - *material instance will be created. The default implementation of this method - *can be used to create the material when no customization is needed. - * @param TilePrim Loaded tile primitive for which a material is needed - * @param pDefaultBaseMaterial Default chosen base material. May be ignored if - *the method chooses to create the mesh material based on a custom base - *material. - * @param Outer The outer for the new material, as used by creation functions - *like NewObject + * Creates a material instance for a given tile primitive. + * The default implementation simply calls `UMaterialInstanceDynamic::Create` + * with the default base material. Overriding this method is useful when a + * different base material should be selected based on properties of the + * primitive. + * @param TilePrimitive Loaded tile primitive for which a material is needed + * @param DefaultBaseMaterial Default chosen base material. May be ignored if + * the method chooses to create the mesh material based on a custom base + * material. * @param Name The name for the new material, as used by creation functions - *like NewObject + * like NewObject * @return Material instance created. If null, a material will be created by - *the caller based on the pBaseMaterial passed, ie. as if this method had not - *been called. + * the caller based on the pBaseMaterial passed, ie. as if this method had not + * been called. */ virtual UMaterialInstanceDynamic* CreateMaterial( - ICesiumLoadedTilePrimitive& TilePrim, - UMaterialInterface* pDefaultBaseMaterial, + ICesiumLoadedTilePrimitive& TilePrimitive, + UMaterialInterface* DefaultBaseMaterial, const FName& Name); /** * Customize the Unreal material instance, depending on the glTF material * definition. - * @param TilePrim Loaded tile primitive to which the material applies + * @param TilePrimitive Loaded tile primitive to which the material applies * @param Material Unreal material created for the primitive - * @param pCesiumData List of material layer names - * @param glTFmaterial Parameters of the glTF material for the primitive - * @param glTFmaterialPBR Parameters for this primitive's material defining the - * metallic-roughness material model from Physically-Based Rendering (PBR) + * @param CesiumData List of material layer names + * @param GlTFmaterial Parameters of the glTF material for the primitive + * @param GlTFmaterialPBR Parameters for this primitive's material defining + * the metallic-roughness material model from Physically-Based Rendering (PBR) * methodology */ virtual void CustomizeMaterial( - ICesiumLoadedTilePrimitive& TilePrim, + ICesiumLoadedTilePrimitive& TilePrimitive, UMaterialInstanceDynamic& Material, - const UCesiumMaterialUserData* pCesiumData, - const CesiumGltf::Material& glTFmaterial, - const CesiumGltf::MaterialPBRMetallicRoughness& glTFmaterialPBR); + const UCesiumMaterialUserData* CesiumData, + const CesiumGltf::Material& GlTFmaterial, + const CesiumGltf::MaterialPBRMetallicRoughness& GlTFmaterialPBR); /** - * Called at the end of the static mesh component construction. - * @param TilePrim Loaded tile primitive being constructed + * Called after a `MeshPrimitive` in a tile's glTF is loaded. This method is + * called at the end of the load process, after construction of the static + * mesh component that will render the primitive. + * + * @param TilePrimitive Tile primitive that has just been loaded. */ virtual void - OnTileMeshPrimitiveConstructed(ICesiumLoadedTilePrimitive& TilePrim); + OnTileMeshPrimitiveLoaded(ICesiumLoadedTilePrimitive& TilePrimitive); /** - * Called at the end of all static mesh components' construction for a given - * tile. - * @param LoadedTile The tile that has just been loaded + * Called after a new tile has been loaded. This method is called after + * `OnTileMeshPrimitiveLoaded` has been called for all of the tile's + * primitives. + * + * @param Tile The tile that has just been loaded */ - virtual void OnTileConstructed(ICesiumLoadedTile& LoadedTile); + virtual void OnTileLoaded(ICesiumLoadedTile& Tile); /** - * Called when changing the visibility of any UCesiumGltfComponent, ie usually - * several times per tile (when the tileset selection leads to showing or - * hiding a whole tile). - * @param LoadedTile The tile which visibility is being toggled - * @param visible New visibility flag being applied + * Called when a tile is shown or hidden. This may be called zero or more + * times per tile. + * @param Tile The tile for which visibility is being toggled + * @param bVisible New visibility flag being applied */ virtual void - OnVisibilityChanged(ICesiumLoadedTile& LoadedTile, bool visible); + OnTileVisibilityChanged(ICesiumLoadedTile& Tile, bool bVisible); /** - * Called before a tile is destroyed (when it is unloaded, typically). - * @param LoadedTile The tile which is about to be unloaded + * Called before a tile is unloaded. + * @param Tile The tile that is about to be unloaded */ - virtual void BeforeTileDestruction(ICesiumLoadedTile& LoadedTile); + virtual void OnTileUnloading(ICesiumLoadedTile& Tile); }; From 67f880cce1138728434ee886365c2c542aa3985d Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 16:07:27 +0200 Subject: [PATCH 18/33] require that CreateMaterial returns non-null --- .../Private/CesiumGltfComponent.cpp | 18 +++++++++--------- .../Cesium3DTilesetLifecycleEventReceiver.h | 4 +--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 48e78b9d0..c0916125e 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3191,15 +3191,15 @@ static void loadPrimitiveGameThreadPart( *pCesiumPrimitive, pBaseMaterial, ImportedSlotName); - if (pMaterialForGltfPrimitive) { - // pMaterialForGltfPrimitive created above may not have used the - // suggested pBaseMaterial passed as input - pBaseMaterial = pMaterialForGltfPrimitive->Parent.Get(); - // may have changed but we don't need it from now on: - pUserDesignatedMaterialAsDynamic = nullptr; - } - } - if (!pMaterialForGltfPrimitive) { + check(pMaterialForGltfPrimitive); + // pMaterialForGltfPrimitive created above may not have used the + // suggested pBaseMaterial passed as input + pBaseMaterial = pMaterialForGltfPrimitive->Parent.Get(); + // may have changed but we don't need it from now on: + pUserDesignatedMaterialAsDynamic = nullptr; + } else { + // Same as ICesium3DTilesetLifecycleEventReceiver::CreateMaterial's + // default implementation pMaterialForGltfPrimitive = UMaterialInstanceDynamic::Create( pBaseMaterial, nullptr, diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index c540c8ebf..0f3455b84 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -50,9 +50,7 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { * material. * @param Name The name for the new material, as used by creation functions * like NewObject - * @return Material instance created. If null, a material will be created by - * the caller based on the pBaseMaterial passed, ie. as if this method had not - * been called. + * @return Material instance created: should not be nullptr. */ virtual UMaterialInstanceDynamic* CreateMaterial( ICesiumLoadedTilePrimitive& TilePrimitive, From ceb051133a5017774be5dc2adf77f0899f5083ed Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 16:18:35 +0200 Subject: [PATCH 19/33] remove the need for GlTFmaterialPBR from CustomizeMaterial and from SetGltfParameterValues, which it probably mimicked in the first place --- .../Cesium3DTilesetLifecycleEventReceiver.cpp | 3 +-- .../CesiumRuntime/Private/CesiumGltfComponent.cpp | 15 ++++----------- .../Cesium3DTilesetLifecycleEventReceiver.h | 6 +----- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp index 7786b50ca..3f097704e 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp @@ -17,8 +17,7 @@ void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial( ICesiumLoadedTilePrimitive& TilePrimitive, UMaterialInstanceDynamic& Material, const UCesiumMaterialUserData* CesiumData, - const CesiumGltf::Material& GlTFmaterial, - const CesiumGltf::MaterialPBRMetallicRoughness& GlTFmaterialPBR) {} + const CesiumGltf::Material& GlTFmaterial) {} void ICesium3DTilesetLifecycleEventReceiver::OnTileMeshPrimitiveLoaded( ICesiumLoadedTilePrimitive& TilePrimitive) {} diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index c0916125e..7e10384d2 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -2480,7 +2480,6 @@ static void SetGltfParameterValues( CesiumGltf::Model& model, LoadedPrimitiveResult& loadResult, const CesiumGltf::Material& material, - const CesiumGltf::MaterialPBRMetallicRoughness& pbr, UMaterialInstanceDynamic* pMaterial, EMaterialParameterAssociation association, int32 index) { @@ -2492,7 +2491,9 @@ static void SetGltfParameterValues( index), static_cast(textureCoordinateSet.second)); } - + const CesiumGltf::MaterialPBRMetallicRoughness& pbr = + material.pbrMetallicRoughness ? material.pbrMetallicRoughness.value() + : defaultPbrMetallicRoughness; if (pbr.baseColorFactor.size() > 3) { pMaterial->SetVectorParameterValueByInfo( FMaterialParameterInfo("baseColorFactor", association, index), @@ -3131,11 +3132,6 @@ static void loadPrimitiveGameThreadPart( const CesiumGltf::Material& material = loadResult.materialIndex != -1 ? model.materials[loadResult.materialIndex] : defaultMaterial; - - const CesiumGltf::MaterialPBRMetallicRoughness& pbr = - material.pbrMetallicRoughness ? material.pbrMetallicRoughness.value() - : defaultPbrMetallicRoughness; - const FName ImportedSlotName( *(TEXT("CesiumMaterial") + FString::FromInt(nextMaterialId++))); @@ -3212,7 +3208,6 @@ static void loadPrimitiveGameThreadPart( model, loadResult, material, - pbr, pMaterialForGltfPrimitive, EMaterialParameterAssociation::GlobalParameter, INDEX_NONE); @@ -3275,7 +3270,6 @@ static void loadPrimitiveGameThreadPart( model, loadResult, material, - pbr, pMaterialForGltfPrimitive, EMaterialParameterAssociation::LayerParameter, 0); @@ -3375,8 +3369,7 @@ static void loadPrimitiveGameThreadPart( *pCesiumPrimitive, *pMaterialForGltfPrimitive, pCesiumData, - material, - pbr); + material); } } diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index 0f3455b84..6adab90b8 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -64,16 +64,12 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { * @param Material Unreal material created for the primitive * @param CesiumData List of material layer names * @param GlTFmaterial Parameters of the glTF material for the primitive - * @param GlTFmaterialPBR Parameters for this primitive's material defining - * the metallic-roughness material model from Physically-Based Rendering (PBR) - * methodology */ virtual void CustomizeMaterial( ICesiumLoadedTilePrimitive& TilePrimitive, UMaterialInstanceDynamic& Material, const UCesiumMaterialUserData* CesiumData, - const CesiumGltf::Material& GlTFmaterial, - const CesiumGltf::MaterialPBRMetallicRoughness& GlTFmaterialPBR); + const CesiumGltf::Material& GlTFmaterial); /** * Called after a `MeshPrimitive` in a tile's glTF is loaded. This method is From 17c87f8caafd3854d81e3362227f33cbe6e218b1 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 16:45:40 +0200 Subject: [PATCH 20/33] bring back GetGltfModel, probably lost during a merge... --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 7 +++++++ Source/CesiumRuntime/Private/CesiumGltfComponent.h | 1 + Source/CesiumRuntime/Public/CesiumLoadedTile.h | 1 + 3 files changed, 9 insertions(+) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 7e10384d2..33259a224 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3578,6 +3578,13 @@ UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() { PrimaryComponentTick.bCanEverTick = false; } +const CesiumGltf::Model* UCesiumGltfComponent::GetGltfModel() const { + if (pTile) + if (auto RenderContent = pTile->getContent().getRenderContent()) + return &RenderContent->getModel(); + return nullptr; +} + const FCesiumModelMetadata& UCesiumGltfComponent::GetModelMetadata() const { return Metadata; } diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index cbd984ab2..ed356cb07 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -138,6 +138,7 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { virtual void OnVisibilityChanged() override; // from ICesiumLoadedTile + const CesiumGltf::Model* GetGltfModel() const override; const FCesiumModelMetadata& GetModelMetadata() const override; const Cesium3DTilesSelection::TileID& GetTileID() const override; ACesium3DTileset& GetTilesetActor() override; diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 4a8c1f27d..6cc350feb 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -25,6 +25,7 @@ class ICesiumLoadedTile { /** Get the tile identifier: this is informational only, as there is no * guarantee of uniqueness */ virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; + virtual const CesiumGltf::Model* GetGltfModel() const = 0; /** Scaling factor to be applied (component-wise multiplication) to glTF * vertices of this tile's model to obtain the values represented in their * matching mesh component (see @{link From 7c8b222515fbf1a0ce8fc5117d36c9c07f54d3da Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 17:13:01 +0200 Subject: [PATCH 21/33] FindTexCoordIndexForGltfAttribute => FindTextureCoordinateIndexForGltfAccessor --- Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp | 4 ++-- Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h | 4 ++-- Source/CesiumRuntime/Public/CesiumLoadedTile.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp index 5cd8f36b9..e1c292a18 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp @@ -170,7 +170,7 @@ ICesiumLoadedTile& UCesiumGltfPrimitiveComponent::GetLoadedTile() { } std::optional -UCesiumGltfPrimitiveComponent::FindTexCoordIndexForGltfAttribute( +UCesiumGltfPrimitiveComponent::FindTextureCoordinateIndexForGltfAccessor( int32_t accessorIndex) const { auto uvIndexIt = getPrimitiveData().GltfToUnrealTexCoordMap.find(accessorIndex); @@ -200,7 +200,7 @@ ICesiumLoadedTile& UCesiumGltfInstancedComponent::GetLoadedTile() { } std::optional -UCesiumGltfInstancedComponent::FindTexCoordIndexForGltfAttribute( +UCesiumGltfInstancedComponent::FindTextureCoordinateIndexForGltfAccessor( int32_t accessorIndex) const { auto uvIndexIt = getPrimitiveData().GltfToUnrealTexCoordMap.find(accessorIndex); diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h index c1293741f..e21834046 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h @@ -48,7 +48,7 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent, ICesiumLoadedTile& GetLoadedTile() override; UStaticMeshComponent& GetMeshComponent() override; std::optional - FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const override; + FindTextureCoordinateIndexForGltfAccessor(int32_t accessorIndex) const override; virtual void OnCreatePhysicsState() override; @@ -83,7 +83,7 @@ class UCesiumGltfInstancedComponent : public UInstancedStaticMeshComponent, ICesiumLoadedTile& GetLoadedTile() override; UStaticMeshComponent& GetMeshComponent() override; std::optional - FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const override; + FindTextureCoordinateIndexForGltfAccessor(int32_t accessorIndex) const override; TSharedPtr pInstanceFeatures; diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 6cc350feb..20d06d3c9 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -50,5 +50,5 @@ class ICesiumLoadedTilePrimitive { virtual const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const = 0; virtual const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const = 0; virtual std::optional - FindTexCoordIndexForGltfAttribute(int32_t accessorIndex) const = 0; + FindTextureCoordinateIndexForGltfAccessor(int32_t AccessorIndex) const = 0; }; From ebd52b11d2a98299f9e610a0e16151f0edb51f52 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 14 Aug 2025 17:13:27 +0200 Subject: [PATCH 22/33] doc comments in CesiumLoadedTile.h --- .../CesiumRuntime/Public/CesiumLoadedTile.h | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 20d06d3c9..551066a69 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -19,36 +19,61 @@ UINTERFACE() class UCesiumLoadedTile : public UInterface { GENERATED_BODY() }; +/** Access to the data loaded when a tile has been selected for display by the + * tileset. + */ class ICesiumLoadedTile { GENERATED_BODY() public: - /** Get the tile identifier: this is informational only, as there is no + /** The tile identifier: this is informational only, as there is no * guarantee of uniqueness */ virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; + /** The glTF model from which the tile data was obtained. */ virtual const CesiumGltf::Model* GetGltfModel() const = 0; - /** Scaling factor to be applied (component-wise multiplication) to glTF + /** The scaling factor to be applied (component-wise multiplication) to glTF * vertices of this tile's model to obtain the values represented in their * matching mesh component (see @{link - * UCesiumLoadedTilePrimitive::GetMeshComponent). */ + * UCesiumLoadedTilePrimitive::GetMeshComponent}). */ virtual FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const = 0; + /** The tileset actor which the tile belongs to. */ virtual ACesium3DTileset& GetTilesetActor() = 0; + /** The blueprint-accessible wrapper for metadata contained in the tile's glTF + * model. */ virtual const FCesiumModelMetadata& GetModelMetadata() const = 0; }; +// Not merged with ICesiumPrimitive because this is Public whereas +// ICesiumPrimitive is Private UINTERFACE() class UCesiumLoadedTilePrimitive : public UInterface { GENERATED_BODY() }; -// Not merged with ICesiumPrimitive because this is Public whereas -// ICesiumPrimitive is Private +/** Access to the data loaded for a given glTF primitive of an {@link + * ICesiumLoadedTile}. + */ class ICesiumLoadedTilePrimitive { GENERATED_BODY() public: + /** The {@link ICesiumLoadedTile} the primitive belongs to. */ virtual ICesiumLoadedTile& GetLoadedTile() = 0; + /** The Unreal mesh component built to represent the glTF primitive. */ virtual UStaticMeshComponent& GetMeshComponent() = 0; + /** The Blueprint-accessible wrapper for the glTF Primitive's mesh features. + */ virtual const FCesiumPrimitiveFeatures& GetPrimitiveFeatures() const = 0; + /** The Blueprint-accessible wrapper for the glTF Primitive's + * EXT_structural_metadata extension */ virtual const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const = 0; + /** The glTF primitive's geometry inside its {@link ICesiumLoadedTile}'s + * model. */ virtual const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const = 0; + /** Maps an accessor index in the glTF primitive to its corresponding texture + * coordinate index in the Unreal mesh. The -1 key is reserved for implicit + * feature IDs (in other words, the vertex index). + * @param AccessorIndex An accessor index in the glTF primitive + * @return A texture coordinate index in the Unreal mesh, or std::nullopt if + * none was found for the AccessorIndex passed. + */ virtual std::optional FindTextureCoordinateIndexForGltfAccessor(int32_t AccessorIndex) const = 0; }; From 42f31ec71b102adb42ddd97722f1c243ae56bba3 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 15:32:23 +1100 Subject: [PATCH 23/33] Move changelog entry to correct version. --- CHANGES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1fb5884ca..25b7037a8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ### ? - ? +##### Additions :tada: + +- Added the interface `ICesium3DTilesetLifecycleEventReceiver`: when an implementation is registered on a tileset (with `ACesium3DTileset::SetLifecycleEventReceiver`), its functions will be called at various points in a tile's lifecycle, like when a mesh component is created, when a material is instanced, when the tile changes visibility, when it is unloaded, etc. + ##### Fixes :wrench: - Fixed a problem where multi-selecting `UCesiumGlobeAnchorComponent` could cause the selected components to teleport to 0 degrees longitude and 0 degrees latitude. Now, the geospatial position and orientation fields are hidden while multi-selecting. @@ -52,10 +56,6 @@ In addition to the above, this release updates [cesium-native](https://github.co - Added `UCesiumPrimitiveMetadataBlueprintLibrary::GetPropertyAttributes` to retrieve the property attributes from a `FCesiumPrimitiveMetadata`. - Added `UCesiumPropertyTexturePropertyBlueprintLibrary::GetInteger64`. Although 64-bit integers aren't directly supported by property textures, this enables the lossless retrieval of 32-bit unsigned integers. -##### Additions :tada: - -- Added the interface `ICesium3DTilesetLifecycleEventReceiver`: when an implementation is registered on a tileset (with `ACesium3DTileset::SetLifecycleEventReceiver`), its functions will be called at various points in a tile's lifecycle, like when a mesh component is created, when a material is instanced, when the tile changes visibility, when it is unloaded, etc. - ##### Fixes :wrench: - Fixed error messages in the Unreal log about uninitialized fields in `FCesiumGeocoderServiceAttribution` and `FCesiumGeocoderServiceFeature`. From ca34f8600fa10d95bdba09e8b171cf8ebed33f4a Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 15:37:59 +1100 Subject: [PATCH 24/33] clang-format --- Source/CesiumRuntime/Private/Cesium3DTileset.cpp | 2 +- .../CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h | 8 ++++---- Source/CesiumRuntime/Private/CesiumPrimitive.h | 2 +- .../Public/Cesium3DTilesetLifecycleEventReceiver.h | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 29c5c52ef..7b1984758 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -10,8 +10,8 @@ #include "Cesium3DTilesSelection/TilesetLoadFailureDetails.h" #include "Cesium3DTilesSelection/TilesetOptions.h" #include "Cesium3DTilesSelection/TilesetSharedAssetSystem.h" -#include "Cesium3DTilesetLoadFailureDetails.h" #include "Cesium3DTilesetLifecycleEventReceiver.h" +#include "Cesium3DTilesetLoadFailureDetails.h" #include "Cesium3DTilesetRoot.h" #include "CesiumActors.h" #include "CesiumAsync/SharedAssetDepot.h" diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h index e21834046..40e8e23d5 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h @@ -47,8 +47,8 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent, // from ICesiumLoadedTilePrimitive ICesiumLoadedTile& GetLoadedTile() override; UStaticMeshComponent& GetMeshComponent() override; - std::optional - FindTextureCoordinateIndexForGltfAccessor(int32_t accessorIndex) const override; + std::optional FindTextureCoordinateIndexForGltfAccessor( + int32_t accessorIndex) const override; virtual void OnCreatePhysicsState() override; @@ -82,8 +82,8 @@ class UCesiumGltfInstancedComponent : public UInstancedStaticMeshComponent, // from ICesiumLoadedTilePrimitive ICesiumLoadedTile& GetLoadedTile() override; UStaticMeshComponent& GetMeshComponent() override; - std::optional - FindTextureCoordinateIndexForGltfAccessor(int32_t accessorIndex) const override; + std::optional FindTextureCoordinateIndexForGltfAccessor( + int32_t accessorIndex) const override; TSharedPtr pInstanceFeatures; diff --git a/Source/CesiumRuntime/Private/CesiumPrimitive.h b/Source/CesiumRuntime/Private/CesiumPrimitive.h index 9b4c5fff0..fc2c54c63 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitive.h +++ b/Source/CesiumRuntime/Private/CesiumPrimitive.h @@ -142,7 +142,7 @@ class ICesiumPrimitive : public ICesiumLoadedTilePrimitive { virtual CesiumPrimitiveData& getPrimitiveData() = 0; virtual const CesiumPrimitiveData& getPrimitiveData() const = 0; -// from ICesiumLoadedTilePrimitive: + // from ICesiumLoadedTilePrimitive: const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const override { return getPrimitiveData().pMeshPrimitive; } diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index 6adab90b8..e140f8337 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -96,8 +96,7 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { * @param Tile The tile for which visibility is being toggled * @param bVisible New visibility flag being applied */ - virtual void - OnTileVisibilityChanged(ICesiumLoadedTile& Tile, bool bVisible); + virtual void OnTileVisibilityChanged(ICesiumLoadedTile& Tile, bool bVisible); /** * Called before a tile is unloaded. From 7e19b17b45264c95ab6c35a1442f0dd74ed6110b Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 16:57:08 +1100 Subject: [PATCH 25/33] Doc tweaks. --- .../CesiumRuntime/Public/CesiumLoadedTile.h | 82 ++++++++++++++----- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/Source/CesiumRuntime/Public/CesiumLoadedTile.h b/Source/CesiumRuntime/Public/CesiumLoadedTile.h index 551066a69..f1ca3a688 100644 --- a/Source/CesiumRuntime/Public/CesiumLoadedTile.h +++ b/Source/CesiumRuntime/Public/CesiumLoadedTile.h @@ -19,26 +19,43 @@ UINTERFACE() class UCesiumLoadedTile : public UInterface { GENERATED_BODY() }; -/** Access to the data loaded when a tile has been selected for display by the - * tileset. + +/** + * Provides access to the details of a tile loaded by the @ref Cesium3DTileset. + * This interface is implemented by the `USceneComponent` subclass that + * represents the tile. */ class ICesiumLoadedTile { GENERATED_BODY() public: - /** The tile identifier: this is informational only, as there is no - * guarantee of uniqueness */ + /** + * Gets the tile identifier: this is informational only, as there is no + * guarantee of uniqueness. + */ virtual const Cesium3DTilesSelection::TileID& GetTileID() const = 0; - /** The glTF model from which the tile data was obtained. */ + + /** + * Gets the glTF model from which the tile data was obtained. + */ virtual const CesiumGltf::Model* GetGltfModel() const = 0; - /** The scaling factor to be applied (component-wise multiplication) to glTF - * vertices of this tile's model to obtain the values represented in their - * matching mesh component (see @{link - * UCesiumLoadedTilePrimitive::GetMeshComponent}). */ + + /** + * Gets the scaling factor that was applied (via component-wise + * multiplication) to the vertices of this tile's glTF model to obtain the + * values represented in the corresponding Unreal mesh components. See @ref + * ICesiumLoadedTilePrimitive::GetMeshComponent}. + */ virtual FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const = 0; - /** The tileset actor which the tile belongs to. */ + + /** + * Gets the tileset Actor that the tile belongs to. + */ virtual ACesium3DTileset& GetTilesetActor() = 0; - /** The blueprint-accessible wrapper for metadata contained in the tile's glTF - * model. */ + + /** + * Gets the blueprint-accessible wrapper for metadata contained in the tile's + * glTF model. + */ virtual const FCesiumModelMetadata& GetModelMetadata() const = 0; }; @@ -48,28 +65,49 @@ UINTERFACE() class UCesiumLoadedTilePrimitive : public UInterface { GENERATED_BODY() }; -/** Access to the data loaded for a given glTF primitive of an {@link - * ICesiumLoadedTile}. + +/** + * Provides access to the details of a glTF `MeshPrimitive` loaded by the @ref + * Cesium3DTileset. This interface is implemented by the `USceneComponent` + * subclass that represents a single glTF primitive that is part of the tile's + * glTF model. */ class ICesiumLoadedTilePrimitive { GENERATED_BODY() public: - /** The {@link ICesiumLoadedTile} the primitive belongs to. */ + /** + * Gets the loaded tile that this primitive belongs to. + */ virtual ICesiumLoadedTile& GetLoadedTile() = 0; - /** The Unreal mesh component built to represent the glTF primitive. */ + + /** + * Gets the Unreal static mesh component built to represent the glTF + * primitive. + */ virtual UStaticMeshComponent& GetMeshComponent() = 0; - /** The Blueprint-accessible wrapper for the glTF Primitive's mesh features. + + /** + * Gets the Blueprint-accessible wrapper for the glTF Primitive's mesh + * features. */ virtual const FCesiumPrimitiveFeatures& GetPrimitiveFeatures() const = 0; - /** The Blueprint-accessible wrapper for the glTF Primitive's - * EXT_structural_metadata extension */ + + /** + * Gets the Blueprint-accessible wrapper for the glTF Primitive's + * `EXT_structural_metadata` extension. + */ virtual const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const = 0; - /** The glTF primitive's geometry inside its {@link ICesiumLoadedTile}'s - * model. */ + + /** + * Gets the glTF primitive. + */ virtual const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const = 0; - /** Maps an accessor index in the glTF primitive to its corresponding texture + + /** + * Maps an accessor index in the glTF primitive to its corresponding texture * coordinate index in the Unreal mesh. The -1 key is reserved for implicit * feature IDs (in other words, the vertex index). + * * @param AccessorIndex An accessor index in the glTF primitive * @return A texture coordinate index in the Unreal mesh, or std::nullopt if * none was found for the AccessorIndex passed. From a08335ee4f17cae63ac98744e5c1d6f058a27a9f Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 17:09:53 +1100 Subject: [PATCH 26/33] Doc tweaks. --- .../Cesium3DTilesetLifecycleEventReceiver.cpp | 2 +- .../Cesium3DTilesetLifecycleEventReceiver.h | 56 ++++++++++++------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp index 3f097704e..9d5183d58 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTilesetLifecycleEventReceiver.cpp @@ -17,7 +17,7 @@ void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial( ICesiumLoadedTilePrimitive& TilePrimitive, UMaterialInstanceDynamic& Material, const UCesiumMaterialUserData* CesiumData, - const CesiumGltf::Material& GlTFmaterial) {} + const CesiumGltf::Material& GltfMaterial) {} void ICesium3DTilesetLifecycleEventReceiver::OnTileMeshPrimitiveLoaded( ICesiumLoadedTilePrimitive& TilePrimitive) {} diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index e140f8337..082ef0696 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -33,24 +33,32 @@ UINTERFACE(meta = (CannotImplementInterfaceInBlueprint)) class UCesium3DTilesetLifecycleEventReceiver : public UInterface { GENERATED_BODY() }; -/** Extension points for customizations requiring mesh and tile properties and - * lifecycle information. All methods are called from the game thread.*/ + +/** + * An interface that receives events about the lifecycle of tiles in a @ref + * Cesium3DTileset. Implement this interface and provide your implementation to + * the tileset by calling @ref SetLifecycleEventReceiver to receive callbacks + * when tiles are loaded, unloaded, hidden, or shown. This interface can also + * customize the Unreal material that is used to render each primitive in each + * tile. + * + * All methods are called from the game thread.*/ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { GENERATED_BODY() public: /** - * Creates a material instance for a given tile primitive. - * The default implementation simply calls `UMaterialInstanceDynamic::Create` - * with the default base material. Overriding this method is useful when a - * different base material should be selected based on properties of the - * primitive. - * @param TilePrimitive Loaded tile primitive for which a material is needed + * Creates a material instance for a given tile primitive. The default + * implementation simply calls `UMaterialInstanceDynamic::Create` with the + * default base material. Overriding this method is useful when a different + * base material should be selected based on properties of the primitive. + * + * @param TilePrimitive Loaded tile primitive for which a material is needed. * @param DefaultBaseMaterial Default chosen base material. May be ignored if * the method chooses to create the mesh material based on a custom base * material. * @param Name The name for the new material, as used by creation functions - * like NewObject - * @return Material instance created: should not be nullptr. + * like NewObject. + * @return Material instance created. Should not be `nullptr`. */ virtual UMaterialInstanceDynamic* CreateMaterial( ICesiumLoadedTilePrimitive& TilePrimitive, @@ -58,18 +66,24 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { const FName& Name); /** - * Customize the Unreal material instance, depending on the glTF material - * definition. - * @param TilePrimitive Loaded tile primitive to which the material applies - * @param Material Unreal material created for the primitive - * @param CesiumData List of material layer names - * @param GlTFmaterial Parameters of the glTF material for the primitive + * Allows customization of the Unreal material instance used to render a + * tile's primitive. This is especially useful for modifying the material + * based on application-specific extensions to the glTF material definition. + * + * This method is called on the Material created by @ref CreateMaterial after + * all of the standard parameters have been set on it. + * + * @param TilePrimitive Loaded tile primitive to which the material applies. + * @param Material The Unreal material created for the primitive. + * @param CesiumData The list of the material's layer names. This can be used to map + * Unreal material layers to specific behavior. + * @param GltfMaterial The glTF material definition. */ virtual void CustomizeMaterial( ICesiumLoadedTilePrimitive& TilePrimitive, UMaterialInstanceDynamic& Material, const UCesiumMaterialUserData* CesiumData, - const CesiumGltf::Material& GlTFmaterial); + const CesiumGltf::Material& GltfMaterial); /** * Called after a `MeshPrimitive` in a tile's glTF is loaded. This method is @@ -93,14 +107,16 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { /** * Called when a tile is shown or hidden. This may be called zero or more * times per tile. - * @param Tile The tile for which visibility is being toggled - * @param bVisible New visibility flag being applied + * + * @param Tile The tile for which visibility is being toggled. + * @param bVisible New visibility flag being applied. */ virtual void OnTileVisibilityChanged(ICesiumLoadedTile& Tile, bool bVisible); /** * Called before a tile is unloaded. - * @param Tile The tile that is about to be unloaded + * + * @param Tile The tile that is about to be unloaded. */ virtual void OnTileUnloading(ICesiumLoadedTile& Tile); }; From 2daba7698e5ec6b6646ad3682f436508ec95c3bc Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 17:10:49 +1100 Subject: [PATCH 27/33] clang-format. --- .../Public/Cesium3DTilesetLifecycleEventReceiver.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h index 082ef0696..35d3b3c99 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h +++ b/Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h @@ -75,8 +75,8 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { * * @param TilePrimitive Loaded tile primitive to which the material applies. * @param Material The Unreal material created for the primitive. - * @param CesiumData The list of the material's layer names. This can be used to map - * Unreal material layers to specific behavior. + * @param CesiumData The list of the material's layer names. This can be used + * to map Unreal material layers to specific behavior. * @param GltfMaterial The glTF material definition. */ virtual void CustomizeMaterial( @@ -107,7 +107,7 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { /** * Called when a tile is shown or hidden. This may be called zero or more * times per tile. - * + * * @param Tile The tile for which visibility is being toggled. * @param bVisible New visibility flag being applied. */ @@ -115,7 +115,7 @@ class CESIUMRUNTIME_API ICesium3DTilesetLifecycleEventReceiver { /** * Called before a tile is unloaded. - * + * * @param Tile The tile that is about to be unloaded. */ virtual void OnTileUnloading(ICesiumLoadedTile& Tile); From f8293a54b743496c0d382cf562b299d0cf4d881e Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 17:14:20 +1100 Subject: [PATCH 28/33] More doc tweaks. --- Source/CesiumRuntime/Public/Cesium3DTileset.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index 14d94f132..3f907fe1e 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -1259,15 +1259,21 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { */ void UpdateTransformFromCesium(); - /** Gets the optional receiver of events related to tile components' lifecycle + /** + * Gets the optional receiver of events related to the lifecycle of tiles + * created by this tileset. */ ICesium3DTilesetLifecycleEventReceiver* GetLifecycleEventReceiver(); - /** Sets a receiver of events related to tile components' lifecycle, - * like tile primitive and material creation, tile finishing its loading cycle - * or about to unload, etc. It must implement - * {@link ICesium3DTilesetLifecycleEventReceiver}, otherwise it will be as if - * nullptr were passed. */ + /** + * Sets a receiver of events related to the lifecycle of tiles + * created by this tileset. + * + * The receiver will be notified of events such as tile load, unload, show, + * and hide. The provided instance _must_ implement @ref + * ICesium3DTilesetLifecycleEventReceiver, otherwise it will be as if nullptr + * were passed. + */ void SetLifecycleEventReceiver(UObject* InEventReceiver); private: From ff67aa477c6e6af9ca1aa642c118baefb383ff23 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 17:18:54 +1100 Subject: [PATCH 29/33] Avoid auto. --- .../CesiumRuntime/Private/UnrealPrepareRendererResources.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp index 07cb4fb92..9f35373d7 100644 --- a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -103,7 +103,8 @@ void UnrealPrepareRendererResources::free( } else if (pMainThreadResult) { UCesiumGltfComponent* pGltf = reinterpret_cast(pMainThreadResult); - if (auto* Receiver = this->_pActor->GetLifecycleEventReceiver()) { + if (ICesium3DTilesetLifecycleEventReceiver* Receiver = + this->_pActor->GetLifecycleEventReceiver()) { Receiver->OnTileUnloading(*pGltf); } CesiumLifetime::destroyComponentRecursively(pGltf); From c8b30066a03c3cb6f095e6eccb623bd261c5be4f Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 17:23:34 +1100 Subject: [PATCH 30/33] Move implementation out of header. --- Source/CesiumRuntime/Private/CesiumPrimitive.cpp | 15 +++++++++++++++ Source/CesiumRuntime/Private/CesiumPrimitive.h | 12 +++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumPrimitive.cpp b/Source/CesiumRuntime/Private/CesiumPrimitive.cpp index 08eb1f774..a6a81a5bb 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitive.cpp +++ b/Source/CesiumRuntime/Private/CesiumPrimitive.cpp @@ -24,3 +24,18 @@ void CesiumPrimitiveData::destroy() { emptyAccessorMap; this->TexCoordAccessorMap.swap(emptyAccessorMap); } + +const CesiumGltf::MeshPrimitive* +ICesiumPrimitive::GetMeshPrimitive() const { + return getPrimitiveData().pMeshPrimitive; +} + +const FCesiumPrimitiveFeatures& +ICesiumPrimitive::GetPrimitiveFeatures() const { + return getPrimitiveData().Features; +} + +const FCesiumPrimitiveMetadata& +ICesiumPrimitive::GetPrimitiveMetadata() const { + return getPrimitiveData().Metadata; +} diff --git a/Source/CesiumRuntime/Private/CesiumPrimitive.h b/Source/CesiumRuntime/Private/CesiumPrimitive.h index fc2c54c63..5f5fb7657 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitive.h +++ b/Source/CesiumRuntime/Private/CesiumPrimitive.h @@ -143,15 +143,9 @@ class ICesiumPrimitive : public ICesiumLoadedTilePrimitive { virtual const CesiumPrimitiveData& getPrimitiveData() const = 0; // from ICesiumLoadedTilePrimitive: - const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const override { - return getPrimitiveData().pMeshPrimitive; - } - const FCesiumPrimitiveFeatures& GetPrimitiveFeatures() const override { - return getPrimitiveData().Features; - } - const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const override { - return getPrimitiveData().Metadata; - } + const CesiumGltf::MeshPrimitive* GetMeshPrimitive() const override; + const FCesiumPrimitiveFeatures& GetPrimitiveFeatures() const override; + const FCesiumPrimitiveMetadata& GetPrimitiveMetadata() const override; virtual void UpdateTransformFromCesium(const glm::dmat4& CesiumToUnrealTransform) = 0; From cf29ac174789846f1ba5f743e1fda3ea22c487be Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 17:24:32 +1100 Subject: [PATCH 31/33] clang-format --- Source/CesiumRuntime/Private/CesiumPrimitive.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumPrimitive.cpp b/Source/CesiumRuntime/Private/CesiumPrimitive.cpp index a6a81a5bb..830ea1682 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitive.cpp +++ b/Source/CesiumRuntime/Private/CesiumPrimitive.cpp @@ -25,17 +25,14 @@ void CesiumPrimitiveData::destroy() { this->TexCoordAccessorMap.swap(emptyAccessorMap); } -const CesiumGltf::MeshPrimitive* -ICesiumPrimitive::GetMeshPrimitive() const { +const CesiumGltf::MeshPrimitive* ICesiumPrimitive::GetMeshPrimitive() const { return getPrimitiveData().pMeshPrimitive; } -const FCesiumPrimitiveFeatures& -ICesiumPrimitive::GetPrimitiveFeatures() const { +const FCesiumPrimitiveFeatures& ICesiumPrimitive::GetPrimitiveFeatures() const { return getPrimitiveData().Features; } -const FCesiumPrimitiveMetadata& -ICesiumPrimitive::GetPrimitiveMetadata() const { +const FCesiumPrimitiveMetadata& ICesiumPrimitive::GetPrimitiveMetadata() const { return getPrimitiveData().Metadata; } From 4bb28fec259c52456454df573889d501d8898dbe Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 18:13:21 +1100 Subject: [PATCH 32/33] Only provide const pointers to tiles. We have recently started forbidding users from accessing non-const Tile pointers. --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 2 +- Source/CesiumRuntime/Private/CesiumGltfComponent.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index b8a228ebe..bee7b1344 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3484,7 +3484,7 @@ UCesiumGltfComponent::CreateOffGameThread( UMaterialInterface* pBaseTranslucentMaterial, UMaterialInterface* pBaseWaterMaterial, FCustomDepthParameters CustomDepthParameters, - Cesium3DTilesSelection::Tile& tile, + const Cesium3DTilesSelection::Tile& tile, bool createNavCollision) { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::LoadModel) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index ed356cb07..ed60207a2 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -89,7 +89,7 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { UMaterialInterface* BaseTranslucentMaterial, UMaterialInterface* BaseWaterMaterial, FCustomDepthParameters CustomDepthParameters, - Cesium3DTilesSelection::Tile& tile, + const Cesium3DTilesSelection::Tile& tile, bool createNavCollision); UCesiumGltfComponent(); @@ -106,7 +106,7 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { UPROPERTY(EditAnywhere, Category = "Rendering") FCustomDepthParameters CustomDepthParameters{}; - Cesium3DTilesSelection::Tile* pTile = nullptr; + const Cesium3DTilesSelection::Tile* pTile = nullptr; FCesiumModelMetadata Metadata{}; EncodedFeaturesMetadata::EncodedModelMetadata EncodedMetadata{}; From 52bd20d836845f599b25b1aee162d061a24f3c07 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Oct 2025 18:21:58 +1100 Subject: [PATCH 33/33] Minor code tweaks. --- Source/CesiumRuntime/Private/CesiumGltfComponent.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index bee7b1344..62590d796 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3544,8 +3544,11 @@ UCesiumGltfComponent::CreateOffGameThread( } } } - if (auto* Receiver = pTilesetActor->GetLifecycleEventReceiver()) + + if (ICesium3DTilesetLifecycleEventReceiver* Receiver = + pTilesetActor->GetLifecycleEventReceiver()) { Receiver->OnTileLoaded(*Gltf); + } Gltf->SetVisibility(false, true); Gltf->SetCollisionEnabled(ECollisionEnabled::NoCollision); @@ -3554,7 +3557,8 @@ UCesiumGltfComponent::CreateOffGameThread( void UCesiumGltfComponent::OnVisibilityChanged() { USceneComponent::OnVisibilityChanged(); - auto* pLifecycleEventReceiver = GetTilesetActor().GetLifecycleEventReceiver(); + ICesium3DTilesetLifecycleEventReceiver* pLifecycleEventReceiver = + GetTilesetActor().GetLifecycleEventReceiver(); if (pLifecycleEventReceiver) pLifecycleEventReceiver->OnTileVisibilityChanged(*this, GetVisibleFlag()); } @@ -3590,9 +3594,10 @@ UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() { } const CesiumGltf::Model* UCesiumGltfComponent::GetGltfModel() const { - if (pTile) + if (pTile) { if (auto RenderContent = pTile->getContent().getRenderContent()) return &RenderContent->getModel(); + } return nullptr; }