From bce28f0bb4c0170e4be29cd15abaf82483e957e4 Mon Sep 17 00:00:00 2001 From: Ghislain Cottat Date: Thu, 13 Nov 2025 15:08:45 +0100 Subject: [PATCH] Added the DoubleSidedCollisions boolean property to the ACesium3DTileset actor Allows intersections and collisions with geometry to also work when hitting "back" faces: most useful when rendering with double sided materials as well, and when the source geometry used to generate the tiles cannot be guaranteed to be properly oriented. Passing false to Chaos::FTriangleMeshImplicitObject's ctor parameter bInCullsBackFaceRaycast had no effect because SetCullsBackFaceRaycast set it back to true some time later (called from ChaosInterface::CreateGeometry through OnRegisterComponent and OnCreatePhysicsState) --- CHANGES.md | 6 ++++++ .../CesiumRuntime/Private/Cesium3DTileset.cpp | 7 +++++++ .../Private/CesiumGltfComponent.cpp | 14 ++++++++++++-- .../CesiumRuntime/Private/CesiumGltfComponent.h | 3 ++- .../Private/UnrealPrepareRendererResources.cpp | 3 ++- Source/CesiumRuntime/Public/Cesium3DTileset.h | 17 +++++++++++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d8b65db4c..2967ca189 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change Log {#changes} +### v?.??.? - ????-??-?? + +##### Additions :tada: + +- Added the `DoubleSidedCollisions` boolean property to the `ACesium3DTileset` actor, allowing intersections and collisions with geometry to also work when hitting "back" faces. + ### v2.21.0 - 2025-11-03 ##### Additions :tada: diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 7b1984758..dd323a1ec 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -492,6 +492,13 @@ void ACesium3DTileset::SetCreatePhysicsMeshes(bool bCreatePhysicsMeshes) { } } +void ACesium3DTileset::SetDoubleSidedCollisions(bool bDoubleSidedCollisions) { + if (this->DoubleSidedCollisions != bDoubleSidedCollisions) { + this->DoubleSidedCollisions = bDoubleSidedCollisions; + this->DestroyTileset(); + } +} + void ACesium3DTileset::SetCreateNavCollision(bool bCreateNavCollision) { if (this->CreateNavCollision != bCreateNavCollision) { this->CreateNavCollision = bCreateNavCollision; diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index 62590d796..671e2c1b1 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -3021,6 +3021,7 @@ static void loadPrimitiveGameThreadPart( const glm::dmat4x4& cesiumToUnrealTransform, const Cesium3DTilesSelection::Tile& tile, bool createNavCollision, + bool doubleSidedCollisions, ACesium3DTileset* pTilesetActor, const std::vector& instanceTransforms, const TSharedPtr& pInstanceFeatures) { @@ -3431,6 +3432,7 @@ static void loadPrimitiveGameThreadPart( ECollisionTraceFlag::CTF_UseComplexAsSimple; if (loadResult.pCollisionMesh) { + pBodySetup->bDoubleSidedGeometry = doubleSidedCollisions; pBodySetup->TriMeshGeometries.Add(loadResult.pCollisionMesh); } @@ -3485,7 +3487,8 @@ UCesiumGltfComponent::CreateOffGameThread( UMaterialInterface* pBaseWaterMaterial, FCustomDepthParameters CustomDepthParameters, const Cesium3DTilesSelection::Tile& tile, - bool createNavCollision) { + bool createNavCollision, + bool doubleSidedCollisions) { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::LoadModel) HalfConstructedReal* pReal = @@ -3538,6 +3541,7 @@ UCesiumGltfComponent::CreateOffGameThread( cesiumToUnrealTransform, tile, createNavCollision, + doubleSidedCollisions, pTilesetActor, node.InstanceTransforms, node.pInstanceFeatures); @@ -3883,5 +3887,11 @@ static Chaos::FTriangleMeshImplicitObjectPtr BuildChaosTriangleMeshes( MoveTemp(materials), MoveTemp(pFaceRemap), nullptr, - false); + // Not sure what this is for: in my experience, whatever you pass here is + // overridden later on by a call to SetCullsBackFaceRaycast (from + // RegisterComponent) which will reset the property depending on the value + // of UBodySetup::bDoubleSidedGeometry. + // See ACesium3DTileset::DoubleSidedCollisions to effectively enable + // backface hits. + /*bInCullsBackFaceRaycast*/false); } diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.h b/Source/CesiumRuntime/Private/CesiumGltfComponent.h index ed60207a2..b9f29c90e 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.h @@ -90,7 +90,8 @@ class UCesiumGltfComponent : public USceneComponent, public ICesiumLoadedTile { UMaterialInterface* BaseWaterMaterial, FCustomDepthParameters CustomDepthParameters, const Cesium3DTilesSelection::Tile& tile, - bool createNavCollision); + bool createNavCollision, + bool doubleSidedCollisions); UCesiumGltfComponent(); diff --git a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp index 9f35373d7..8e11ed8e1 100644 --- a/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp +++ b/Source/CesiumRuntime/Private/UnrealPrepareRendererResources.cpp @@ -85,7 +85,8 @@ void* UnrealPrepareRendererResources::prepareInMainThread( this->_pActor->GetWaterMaterial(), this->_pActor->GetCustomDepthParameters(), tile, - this->_pActor->GetCreateNavCollision()); + this->_pActor->GetCreateNavCollision(), + this->_pActor->GetDoubleSidedCollisions()); } // UE_LOG(LogCesium, VeryVerbose, TEXT("No content for tile")); return nullptr; diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index 3f907fe1e..2a0e080b0 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -799,6 +799,17 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { Category = "Cesium|Physics") bool CreatePhysicsMeshes = true; + /** + * Whether to enable doubled-sided collisions (both "front" and "back" faces) + * on the physics meshes created when CreatePhysicsMeshes is true. + */ + UPROPERTY( + EditAnywhere, + BlueprintGetter = GetDoubleSidedCollisions, + BlueprintSetter = SetDoubleSidedCollisions, + Category = "Cesium|Physics") + bool DoubleSidedCollisions = false; + /** * Whether to generate navigation collisions for this tileset. * @@ -1095,6 +1106,12 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { UFUNCTION(BlueprintSetter, Category = "Cesium|Physics") void SetCreatePhysicsMeshes(bool bCreatePhysicsMeshes); + UFUNCTION(BlueprintGetter, Category = "Cesium|Physics") + bool GetDoubleSidedCollisions() const { return DoubleSidedCollisions; } + + UFUNCTION(BlueprintSetter, Category = "Cesium|Physics") + void SetDoubleSidedCollisions(bool bCreatePhysicsMeshes); + UFUNCTION(BlueprintGetter, Category = "Cesium|Navigation") bool GetCreateNavCollision() const { return CreateNavCollision; }