Skip to content

Commit ec3ab7b

Browse files
committed
Merge branch 'main' into basic-voxel-support
2 parents 7d84c24 + 6f9822d commit ec3ab7b

17 files changed

+515
-28
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
##### Additions :tada:
66

77
- Added support for tilesets containing `3DTILES_content_voxels`. Voxel metadata can be styled with materials generated by `UCesiumVoxelMetadataComponent`.
8+
- 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.
89

910
##### Fixes :wrench:
1011

Source/CesiumRuntime/Private/Cesium3DTileset.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// Copyright 2020-2024 CesiumGS, Inc. and Contributors
22

33
#include "Cesium3DTileset.h"
4+
45
#include "Async/Async.h"
56
#include "Camera/CameraTypes.h"
67
#include "Camera/PlayerCameraManager.h"
8+
#include "Cesium3DTilesetLifecycleEventReceiver.h"
79
#include "Cesium3DTilesetLoadFailureDetails.h"
810
#include "Cesium3DTilesetRoot.h"
911
#include "CesiumActors.h"
@@ -60,6 +62,7 @@
6062

6163
#ifdef CESIUM_DEBUG_TILE_STATES
6264
#include "HAL/PlatformFileManager.h"
65+
6366
#include <Cesium3DTilesSelection/DebugTileStateDatabase.h>
6467
#endif
6568

@@ -2413,3 +2416,16 @@ void ACesium3DTileset::createVoxelRenderer(
24132416
}
24142417
}
24152418
}
2419+
2420+
ICesium3DTilesetLifecycleEventReceiver*
2421+
ACesium3DTileset::GetLifecycleEventReceiver() {
2422+
return Cast<ICesium3DTilesetLifecycleEventReceiver>(
2423+
this->_pLifecycleEventReceiver);
2424+
}
2425+
2426+
void ACesium3DTileset::SetLifecycleEventReceiver(UObject* InEventReceiver) {
2427+
if (UKismetSystemLibrary::DoesImplementInterface(
2428+
InEventReceiver,
2429+
UCesium3DTilesetLifecycleEventReceiver::StaticClass()))
2430+
this->_pLifecycleEventReceiver = InEventReceiver;
2431+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2020-2025 CesiumGS, Inc. and Contributors
2+
3+
#include "Cesium3DTilesetLifecycleEventReceiver.h"
4+
5+
#include "Materials/MaterialInstanceDynamic.h"
6+
7+
UMaterialInstanceDynamic*
8+
ICesium3DTilesetLifecycleEventReceiver::CreateMaterial(
9+
ICesiumLoadedTilePrimitive& TilePrimitive,
10+
UMaterialInterface* DefaultBaseMaterial,
11+
const FName& Name) {
12+
// Default implementation: just create a new instance
13+
return UMaterialInstanceDynamic::Create(DefaultBaseMaterial, nullptr, Name);
14+
}
15+
16+
void ICesium3DTilesetLifecycleEventReceiver::CustomizeMaterial(
17+
ICesiumLoadedTilePrimitive& TilePrimitive,
18+
UMaterialInstanceDynamic& Material,
19+
const UCesiumMaterialUserData* CesiumData,
20+
const CesiumGltf::Material& GltfMaterial) {}
21+
22+
void ICesium3DTilesetLifecycleEventReceiver::OnTileMeshPrimitiveLoaded(
23+
ICesiumLoadedTilePrimitive& TilePrimitive) {}
24+
25+
void ICesium3DTilesetLifecycleEventReceiver::OnTileLoaded(
26+
ICesiumLoadedTile& Tile) {}
27+
28+
void ICesium3DTilesetLifecycleEventReceiver::OnTileVisibilityChanged(
29+
ICesiumLoadedTile& Tile,
30+
bool bVisible) {}
31+
32+
void ICesium3DTilesetLifecycleEventReceiver::OnTileUnloading(
33+
ICesiumLoadedTile& Tile) {}

Source/CesiumRuntime/Private/CesiumGltfComponent.cpp

Lines changed: 95 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright 2020-2024 CesiumGS, Inc. and Contributors
22

33
#include "CesiumGltfComponent.h"
4+
45
#include "Async/Async.h"
6+
#include "Cesium3DTilesetLifecycleEventReceiver.h"
57
#include "CesiumCommon.h"
68
#include "CesiumEncodedMetadataUtility.h"
79
#include "CesiumFeatureIdSet.h"
@@ -1555,6 +1557,8 @@ static void loadPrimitive(
15551557
positionBuffer.Init(numVertices, false);
15561558

15571559
{
1560+
// Note: scaling from glTF vertices to Unreal's must match
1561+
// UCesiumGltfComponent::GetGltfToUnrealLocalVertexPositionScaleFactor
15581562
if (duplicateVertices) {
15591563
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::CopyDuplicatedPositions)
15601564
for (uint32 i = 0; i < numVertices; ++i) {
@@ -2626,7 +2630,6 @@ static void SetGltfParameterValues(
26262630
CesiumGltf::Model& model,
26272631
LoadedPrimitiveResult& loadResult,
26282632
const CesiumGltf::Material& material,
2629-
const CesiumGltf::MaterialPBRMetallicRoughness& pbr,
26302633
UMaterialInstanceDynamic* pMaterial,
26312634
EMaterialParameterAssociation association,
26322635
int32 index) {
@@ -2638,7 +2641,9 @@ static void SetGltfParameterValues(
26382641
index),
26392642
static_cast<float>(textureCoordinateSet.second));
26402643
}
2641-
2644+
const CesiumGltf::MaterialPBRMetallicRoughness& pbr =
2645+
material.pbrMetallicRoughness ? material.pbrMetallicRoughness.value()
2646+
: defaultPbrMetallicRoughness;
26422647
if (pbr.baseColorFactor.size() > 3) {
26432648
pMaterial->SetVectorParameterValueByInfo(
26442649
FMaterialParameterInfo("baseColorFactor", association, index),
@@ -3293,11 +3298,6 @@ static void loadPrimitiveGameThreadPart(
32933298
const CesiumGltf::Material& material =
32943299
loadResult.materialIndex != -1 ? model.materials[loadResult.materialIndex]
32953300
: defaultMaterial;
3296-
3297-
const CesiumGltf::MaterialPBRMetallicRoughness& pbr =
3298-
material.pbrMetallicRoughness ? material.pbrMetallicRoughness.value()
3299-
: defaultPbrMetallicRoughness;
3300-
33013301
const FName ImportedSlotName(
33023302
*(TEXT("CesiumMaterial") + FString::FromInt(nextMaterialId++)));
33033303

@@ -3323,13 +3323,22 @@ static void loadPrimitiveGameThreadPart(
33233323
}
33243324
#endif
33253325

3326-
UMaterialInstanceDynamic* pMaterialForGltfPrimitive;
3326+
// Move this right now: CreateMaterial may need them!
3327+
// "Safe" even though loadResult is still used later, because the methods used
3328+
// during material setup (SetGltfParameterValues, etc.) below do not use these
3329+
// members.
3330+
primData.Features = std::move(loadResult.Features);
3331+
primData.Metadata = std::move(loadResult.Metadata);
3332+
3333+
UMaterialInstanceDynamic* pMaterialForGltfPrimitive = nullptr;
3334+
ICesium3DTilesetLifecycleEventReceiver* pLifecycleEventReceiver =
3335+
pTilesetActor->GetLifecycleEventReceiver();
33273336
{
33283337
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::SetupMaterial)
3338+
ensure(pUserDesignatedMaterial);
33293339

33303340
UMaterialInstanceDynamic* pUserDesignatedMaterialAsDynamic =
33313341
Cast<UMaterialInstanceDynamic>(pUserDesignatedMaterial);
3332-
33333342
// If the user-designated material is a UMaterialInstanceDynamic, Create()
33343343
// will reject it as a valid instance parent. Defer to its non-dynamic
33353344
// parent instead.
@@ -3338,18 +3347,33 @@ static void loadPrimitiveGameThreadPart(
33383347
? pUserDesignatedMaterialAsDynamic->Parent.Get()
33393348
: pUserDesignatedMaterial;
33403349

3341-
pMaterialForGltfPrimitive = UMaterialInstanceDynamic::Create(
3342-
pBaseMaterial,
3343-
nullptr,
3344-
ImportedSlotName);
3350+
if (pLifecycleEventReceiver) {
3351+
// Possibility to override the material for this primitive
3352+
pMaterialForGltfPrimitive = pLifecycleEventReceiver->CreateMaterial(
3353+
*pCesiumPrimitive,
3354+
pBaseMaterial,
3355+
ImportedSlotName);
3356+
check(pMaterialForGltfPrimitive);
3357+
// pMaterialForGltfPrimitive created above may not have used the
3358+
// suggested pBaseMaterial passed as input
3359+
pBaseMaterial = pMaterialForGltfPrimitive->Parent.Get();
3360+
// may have changed but we don't need it from now on:
3361+
pUserDesignatedMaterialAsDynamic = nullptr;
3362+
} else {
3363+
// Same as ICesium3DTilesetLifecycleEventReceiver::CreateMaterial's
3364+
// default implementation
3365+
pMaterialForGltfPrimitive = UMaterialInstanceDynamic::Create(
3366+
pBaseMaterial,
3367+
nullptr,
3368+
ImportedSlotName);
3369+
}
33453370

33463371
pMaterialForGltfPrimitive->SetFlags(
33473372
RF_Transient | RF_DuplicateTransient | RF_TextExportTransient);
33483373
SetGltfParameterValues(
33493374
model,
33503375
loadResult,
33513376
material,
3352-
pbr,
33533377
pMaterialForGltfPrimitive,
33543378
EMaterialParameterAssociation::GlobalParameter,
33553379
INDEX_NONE);
@@ -3412,7 +3436,6 @@ static void loadPrimitiveGameThreadPart(
34123436
model,
34133437
loadResult,
34143438
material,
3415-
pbr,
34163439
pMaterialForGltfPrimitive,
34173440
EMaterialParameterAssociation::LayerParameter,
34183441
0);
@@ -3505,10 +3528,16 @@ static void loadPrimitiveGameThreadPart(
35053528
it.FontPage);
35063529
}
35073530
}
3508-
}
35093531

3510-
primData.Features = std::move(loadResult.Features);
3511-
primData.Metadata = std::move(loadResult.Metadata);
3532+
// Extra material customizations
3533+
if (pLifecycleEventReceiver) {
3534+
pLifecycleEventReceiver->CustomizeMaterial(
3535+
*pCesiumPrimitive,
3536+
*pMaterialForGltfPrimitive,
3537+
pCesiumData,
3538+
material);
3539+
}
3540+
}
35123541

35133542
primData.EncodedFeatures = std::move(loadResult.EncodedFeatures);
35143543
primData.EncodedMetadata = std::move(loadResult.EncodedMetadata);
@@ -3581,6 +3610,11 @@ static void loadPrimitiveGameThreadPart(
35813610
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::RegisterComponent)
35823611
pMesh->RegisterComponent();
35833612
}
3613+
3614+
// Call the observer callback (if any) once all is done
3615+
if (pLifecycleEventReceiver) {
3616+
pLifecycleEventReceiver->OnTileMeshPrimitiveLoaded(*pCesiumPrimitive);
3617+
}
35843618
}
35853619

35863620
static void loadVoxelsGameThreadPart(
@@ -3667,6 +3701,7 @@ UCesiumGltfComponent::CreateOffGameThread(
36673701
// }
36683702

36693703
UCesiumGltfComponent* pGltf = NewObject<UCesiumGltfComponent>(pTilesetActor);
3704+
pGltf->pTile = &tile;
36703705
pGltf->SetMobility(pTilesetActor->GetRootComponent()->Mobility);
36713706
pGltf->SetFlags(
36723707
RF_Transient | RF_DuplicateTransient | RF_TextExportTransient);
@@ -3723,11 +3758,24 @@ UCesiumGltfComponent::CreateOffGameThread(
37233758
}
37243759
}
37253760

3761+
if (ICesium3DTilesetLifecycleEventReceiver* Receiver =
3762+
pTilesetActor->GetLifecycleEventReceiver()) {
3763+
Receiver->OnTileLoaded(*pGltf);
3764+
}
3765+
37263766
pGltf->SetVisibility(false, true);
37273767
pGltf->SetCollisionEnabled(ECollisionEnabled::NoCollision);
37283768
return pGltf;
37293769
}
37303770

3771+
void UCesiumGltfComponent::OnVisibilityChanged() {
3772+
USceneComponent::OnVisibilityChanged();
3773+
ICesium3DTilesetLifecycleEventReceiver* pLifecycleEventReceiver =
3774+
GetTilesetActor().GetLifecycleEventReceiver();
3775+
if (pLifecycleEventReceiver)
3776+
pLifecycleEventReceiver->OnTileVisibilityChanged(*this, GetVisibleFlag());
3777+
}
3778+
37313779
UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() {
37323780
// Structure to hold one-time initialization
37333781
struct FConstructorStatics {
@@ -3758,6 +3806,35 @@ UCesiumGltfComponent::UCesiumGltfComponent() : USceneComponent() {
37583806
PrimaryComponentTick.bCanEverTick = false;
37593807
}
37603808

3809+
const CesiumGltf::Model* UCesiumGltfComponent::GetGltfModel() const {
3810+
if (pTile) {
3811+
if (auto RenderContent = pTile->getContent().getRenderContent())
3812+
return &RenderContent->getModel();
3813+
}
3814+
return nullptr;
3815+
}
3816+
3817+
const FCesiumModelMetadata& UCesiumGltfComponent::GetModelMetadata() const {
3818+
return Metadata;
3819+
}
3820+
3821+
const Cesium3DTilesSelection::TileID& UCesiumGltfComponent::GetTileID() const {
3822+
return pTile->getTileID();
3823+
}
3824+
3825+
ACesium3DTileset& UCesiumGltfComponent::GetTilesetActor() {
3826+
return *Cast<ACesium3DTileset>(GetOuter());
3827+
}
3828+
3829+
FVector
3830+
UCesiumGltfComponent::GetGltfToUnrealLocalVertexPositionScaleFactor() const {
3831+
// Note: replicates logic from (static) loadPrimitive
3832+
return FVector(
3833+
CesiumPrimitiveData::positionScaleFactor,
3834+
-CesiumPrimitiveData::positionScaleFactor,
3835+
CesiumPrimitiveData::positionScaleFactor);
3836+
}
3837+
37613838
void UCesiumGltfComponent::UpdateTransformFromCesium(
37623839
const glm::dmat4& cesiumToUnrealTransform) {
37633840
for (USceneComponent* pSceneComponent : this->GetAttachChildren()) {

Source/CesiumRuntime/Private/CesiumGltfComponent.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
#include "Cesium3DTilesSelection/Tile.h"
66
#include "Cesium3DTileset.h"
77
#include "CesiumEncodedMetadataUtility.h"
8+
#include "CesiumLoadedTile.h"
89
#include "CesiumModelMetadata.h"
910
#include "Components/PrimitiveComponent.h"
1011
#include "Components/SceneComponent.h"
1112
#include "CoreMinimal.h"
1213
#include "CustomDepthParameters.h"
1314
#include "EncodedFeaturesMetadata.h"
1415
#include "Interfaces/IHttpRequest.h"
16+
#include "Templates/Function.h"
1517
#include <CesiumAsync/SharedFuture.h>
1618
#include <glm/mat4x4.hpp>
1719
#include <memory>
@@ -56,7 +58,7 @@ struct FRasterOverlayTile {
5658
};
5759

5860
UCLASS()
59-
class UCesiumGltfComponent : public USceneComponent {
61+
class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile {
6062
GENERATED_BODY()
6163

6264
public:
@@ -104,6 +106,8 @@ class UCesiumGltfComponent : public USceneComponent {
104106
UPROPERTY(EditAnywhere, Category = "Rendering")
105107
FCustomDepthParameters CustomDepthParameters{};
106108

109+
const Cesium3DTilesSelection::Tile* pTile = nullptr;
110+
107111
FCesiumModelMetadata Metadata{};
108112
EncodedFeaturesMetadata::EncodedModelMetadata EncodedMetadata{};
109113

@@ -131,6 +135,14 @@ class UCesiumGltfComponent : public USceneComponent {
131135
virtual void SetCollisionEnabled(ECollisionEnabled::Type NewType);
132136

133137
virtual void BeginDestroy() override;
138+
virtual void OnVisibilityChanged() override;
139+
140+
// from ICesiumLoadedTile
141+
const CesiumGltf::Model* GetGltfModel() const override;
142+
const FCesiumModelMetadata& GetModelMetadata() const override;
143+
const Cesium3DTilesSelection::TileID& GetTileID() const override;
144+
ACesium3DTileset& GetTilesetActor() override;
145+
FVector GetGltfToUnrealLocalVertexPositionScaleFactor() const override;
134146

135147
void UpdateFade(float fadePercentage, bool fadingIn);
136148

0 commit comments

Comments
 (0)