bmh/FlightSimulation/Plugins/CesiumForUnreal_5.4/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp
2025-02-07 22:52:32 +08:00

170 lines
5.2 KiB
C++

// 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 <CesiumGltf/MeshPrimitive.h>
#include <CesiumGltf/Model.h>
#include <variant>
// 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<ICesiumPrimitive>(pComponent);
cesiumPrimitive->getPrimitiveData().destroy();
UMaterialInstanceDynamic* pMaterial =
Cast<UMaterialInstanceDynamic>(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<FBoxSphereBounds>
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 <typename CesiumComponent>
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;
}