// Copyright 2020-2024 CesiumGS, Inc. and Contributors #include "CesiumGltfPrimitiveComponent.h" #include "CalcBounds.h" #include "CesiumLifetime.h" #include "CesiumMaterialUserData.h" #include "Engine/Texture.h" #include "Materials/MaterialInstanceDynamic.h" #include "PhysicsEngine/BodySetup.h" #include "VecMath.h" #include #include #include // Prevent deprecation warnings while initializing deprecated metadata structs. PRAGMA_DISABLE_DEPRECATION_WARNINGS // Sets default values for this component's properties UCesiumGltfPrimitiveComponent::UCesiumGltfPrimitiveComponent() { PrimaryComponentTick.bCanEverTick = false; } UCesiumGltfInstancedComponent::UCesiumGltfInstancedComponent() { PrimaryComponentTick.bCanEverTick = false; } PRAGMA_ENABLE_DEPRECATION_WARNINGS UCesiumGltfPrimitiveComponent::~UCesiumGltfPrimitiveComponent() {} UCesiumGltfInstancedComponent::~UCesiumGltfInstancedComponent() {} namespace { void destroyCesiumPrimitive(UStaticMeshComponent* pComponent) { // Clear everything we can in order to reduce memory usage, because this // UObject might not actually get deleted by the garbage collector until // much later. auto* cesiumPrimitive = Cast(pComponent); cesiumPrimitive->getPrimitiveData().destroy(); UMaterialInstanceDynamic* pMaterial = Cast(pComponent->GetMaterial(0)); if (pMaterial) { CesiumLifetime::destroy(pMaterial); } UStaticMesh* pMesh = pComponent->GetStaticMesh(); if (pMesh) { UBodySetup* pBodySetup = pMesh->GetBodySetup(); if (pBodySetup) { CesiumLifetime::destroy(pBodySetup); } CesiumLifetime::destroy(pMesh); } } } // namespace void UCesiumGltfPrimitiveComponent::BeginDestroy() { destroyCesiumPrimitive(this); Super::BeginDestroy(); } void UCesiumGltfInstancedComponent::BeginDestroy() { destroyCesiumPrimitive(this); Super::BeginDestroy(); } namespace { std::optional calcBounds(const ICesiumPrimitive& primitive, const FTransform& LocalToWorld) { const CesiumPrimitiveData& primData = primitive.getPrimitiveData(); if (!primData.boundingVolume) { return std::nullopt; } return std::visit( CalcBoundsOperation{LocalToWorld, primData.HighPrecisionNodeTransform}, *primData.boundingVolume); } } // namespace FBoxSphereBounds UCesiumGltfPrimitiveComponent::CalcBounds( const FTransform& LocalToWorld) const { if (auto bounds = calcBounds(*this, LocalToWorld)) { return *bounds; } return Super::CalcBounds(LocalToWorld); } FBoxSphereBounds UCesiumGltfInstancedComponent::CalcBounds( const FTransform& LocalToWorld) const { if (auto bounds = calcBounds(*this, LocalToWorld)) { return *bounds; } return Super::CalcBounds(LocalToWorld); } namespace { // Returns true if the component is moveable, so caller can "Do The Right // Thing." This avoids making the protected member function SendPhysicsTransform // public. template bool UpdateTransformFromCesiumAux( const glm::dmat4& CesiumToUnrealTransform, CesiumComponent* cesiumComponent) { const CesiumPrimitiveData& primData = cesiumComponent->getPrimitiveData(); const FTransform transform = VecMath::createTransform( CesiumToUnrealTransform * primData.HighPrecisionNodeTransform); if (cesiumComponent->Mobility == EComponentMobility::Movable) { // For movable objects, move the component in the normal way, but don't // generate collisions along the way. Teleporting physics is imperfect, // but it's the best available option. cesiumComponent->SetRelativeTransform( transform, false, nullptr, ETeleportType::TeleportPhysics); return true; } // Unreal will yell at us for calling SetRelativeTransform on a static // object, but we still need to adjust (accurately!) for origin rebasing // and georeference changes. It's "ok" to move a static object in this way // because, we assume, the globe and globe-oriented lights, etc. are // moving too, so in a relative sense the object isn't actually moving. // This isn't a perfect assumption, of course. cesiumComponent->SetRelativeTransform_Direct(transform); cesiumComponent->UpdateComponentToWorld(); cesiumComponent->MarkRenderTransformDirty(); return false; } } // namespace void UCesiumGltfPrimitiveComponent::UpdateTransformFromCesium( const glm::dmat4& CesiumToUnrealTransform) { bool moveable = UpdateTransformFromCesiumAux(CesiumToUnrealTransform, this); if (!moveable) { SendPhysicsTransform(ETeleportType::ResetPhysics); } } void UCesiumGltfInstancedComponent::UpdateTransformFromCesium( const glm::dmat4& CesiumToUnrealTransform) { bool moveable = UpdateTransformFromCesiumAux(CesiumToUnrealTransform, this); if (!moveable) { SendPhysicsTransform(ETeleportType::ResetPhysics); } } CesiumPrimitiveData& UCesiumGltfPrimitiveComponent::getPrimitiveData() { return _cesiumData; } const CesiumPrimitiveData& UCesiumGltfPrimitiveComponent::getPrimitiveData() const { return _cesiumData; } CesiumPrimitiveData& UCesiumGltfInstancedComponent::getPrimitiveData() { return _cesiumData; } const CesiumPrimitiveData& UCesiumGltfInstancedComponent::getPrimitiveData() const { return _cesiumData; }