Files
UnrealEngine/Engine/Plugins/Runtime/nDisplay/Source/DisplayClusterWarp/Private/Components/DisplayClusterInFrustumFitCameraComponent.cpp
2025-05-18 13:04:45 +08:00

263 lines
9.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Components/DisplayClusterInFrustumFitCameraComponent.h"
#include "Components/BillboardComponent.h"
#include "CineCameraActor.h"
#include "Camera/CameraComponent.h"
#include "CineCameraComponent.h"
#include "DisplayClusterWarpLog.h"
#include "PDisplayClusterWarpStrings.h"
#include "IDisplayCluster.h"
#include "IDisplayClusterWarpBlend.h"
#include "Render/IDisplayClusterRenderManager.h"
#include "Render/Viewport/IDisplayClusterViewportManager.h"
#include "Render/Viewport/IDisplayClusterViewport.h"
#include "Render/Projection/IDisplayClusterProjectionPolicy.h"
#include "Render/Warp/IDisplayClusterWarpPolicyFactory.h"
#include "Render/Warp/IDisplayClusterWarpPolicy.h"
#include "Materials/Material.h"
#include "UObject/ConstructorHelpers.h"
#include "DisplayClusterRootActor.h"
namespace UE::DisplayClusterWarp::ViewPointComponent
{
static inline TSharedPtr<IDisplayClusterWarpPolicy, ESPMode::ThreadSafe> ImplCreateWarpPolicy(const FString& InWarpPolicyType, const FString& InWarpPolicyName)
{
static IDisplayCluster& DisplayClusterSingleton = IDisplayCluster::Get();
if (IDisplayClusterRenderManager* const DCRenderManager = DisplayClusterSingleton.GetRenderMgr())
{
TSharedPtr<IDisplayClusterWarpPolicyFactory> WarpPolicyFactory = DCRenderManager->GetWarpPolicyFactory(InWarpPolicyType);
if (WarpPolicyFactory.IsValid())
{
return WarpPolicyFactory->Create(InWarpPolicyType, InWarpPolicyName);
}
}
return nullptr;
}
};
//--------------------------------------------------------------------------------
// UDisplayClusterInFrustumFitCameraComponent
//--------------------------------------------------------------------------------
UDisplayClusterInFrustumFitCameraComponent::UDisplayClusterInFrustumFitCameraComponent(const FObjectInitializer& ObjectInitializer)
: UDisplayClusterCameraComponent(ObjectInitializer)
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickGroup = TG_PostUpdateWork;
PrimaryComponentTick.bStartWithTickEnabled = true;
bAutoActivate = true;
}
TObjectPtr<UMaterial> UDisplayClusterInFrustumFitCameraComponent::GetDisplayDeviceMaterial(const EDisplayClusterDisplayDeviceMeshType InMeshType, const EDisplayClusterDisplayDeviceMaterialType InMaterialType) const
{
// Uses its own material to display additional deformed preview meshes in front of the camera.
if (IsEnabled() && WarpPolicy.IsValid())
{
// Special preview material is used for editable meshes: they should fly in front of the camera and deform according to its frustum.
if (InMeshType == EDisplayClusterDisplayDeviceMeshType::PreviewEditableMesh)
{
static TObjectPtr<UMaterial> InFrustumFitMaterial = LoadObject<UMaterial>(nullptr, UE::DisplayClusterWarpStrings::InFrustumFit::material::Name, nullptr, LOAD_None, nullptr);
if (InFrustumFitMaterial && InMeshType == EDisplayClusterDisplayDeviceMeshType::PreviewEditableMesh)
{
switch (InMaterialType)
{
case EDisplayClusterDisplayDeviceMaterialType::PreviewMeshMaterial:
case EDisplayClusterDisplayDeviceMaterialType::PreviewMeshTechvisMaterial:
// Note: Add additional techvis material for 'InFrustumFitCamera' if needed.
return InFrustumFitMaterial.Get();
default:
break;
}
}
}
}
return nullptr;
}
void UDisplayClusterInFrustumFitCameraComponent::OnUpdateDisplayDeviceMeshAndMaterialInstance(IDisplayClusterViewportPreview& InViewportPreview, const EDisplayClusterDisplayDeviceMeshType InMeshType, const EDisplayClusterDisplayDeviceMaterialType InMaterialType, UMeshComponent* InMeshComponent, UMaterialInstanceDynamic* InMeshMaterialInstance) const
{
if (IsEnabled() && WarpPolicy.IsValid())
{
// The preview material used for editable meshes requires a set of unique parameters that are set from the warp policy.
if (InMeshComponent && InMeshMaterialInstance && InMeshType == EDisplayClusterDisplayDeviceMeshType::PreviewEditableMesh)
{
switch (InMaterialType)
{
case EDisplayClusterDisplayDeviceMaterialType::PreviewMeshMaterial:
case EDisplayClusterDisplayDeviceMaterialType::PreviewMeshTechvisMaterial:
WarpPolicy->OnUpdateDisplayDeviceMeshAndMaterialInstance(InViewportPreview, InMeshType, InMaterialType, InMeshComponent, InMeshMaterialInstance);
break;
default:
break;
}
}
}
}
const UDisplayClusterInFrustumFitCameraComponent& UDisplayClusterInFrustumFitCameraComponent::GetConfigurationInFrustumFitCameraComponent(IDisplayClusterViewportConfiguration& InViewportConfiguration) const
{
if (ADisplayClusterRootActor* ConfigurationRootActor = InViewportConfiguration.GetRootActor(EDisplayClusterRootActorType::Configuration))
{
if (ConfigurationRootActor != GetOwner())
{
if (UDisplayClusterInFrustumFitCameraComponent* ConfigurationCameraComponent = ConfigurationRootActor->GetComponentByName<UDisplayClusterInFrustumFitCameraComponent>(GetName()))
{
return *ConfigurationCameraComponent;
}
}
}
return *this;
}
bool UDisplayClusterInFrustumFitCameraComponent::IsEnabled() const
{
return bEnableCameraProjection;
}
bool UDisplayClusterInFrustumFitCameraComponent::IsICVFXCameraBeingUsed() const
{
// When using InFrustum projection, ignore the camera component from the parent class
if (IsEnabled())
{
return false;
}
return Super::IsICVFXCameraBeingUsed();
}
bool UDisplayClusterInFrustumFitCameraComponent::IsViewPointOverrideCameraPosition() const
{
// If InFrustumFit uses an external camera, use it as a ViewPoint.
if (IsEnabled())
{
return false;
}
return Super::IsViewPointOverrideCameraPosition();
}
void UDisplayClusterInFrustumFitCameraComponent::GetEyePosition(const IDisplayClusterViewportConfiguration& InViewportConfiguration, FVector& OutViewLocation, FRotator& OutViewRotation)
{
Super::GetEyePosition(InViewportConfiguration, OutViewLocation, OutViewRotation);
// The observer's eye is located inside the InFrustumFit component.
if (IsEnabled())
{
OutViewLocation = GetComponentLocation();
OutViewRotation = GetComponentRotation();
}
}
void UDisplayClusterInFrustumFitCameraComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
// Tick warp policy instance
if (WarpPolicy.IsValid())
{
if (ADisplayClusterRootActor* ParentRootActor = Cast<ADisplayClusterRootActor>(GetOwner()))
{
if (IDisplayClusterViewportManager* ViewportManager = ParentRootActor->GetViewportManager())
{
WarpPolicy->Tick(ViewportManager, DeltaTime);
}
}
}
}
bool UDisplayClusterInFrustumFitCameraComponent::ShouldUseEntireClusterViewports(IDisplayClusterViewportManager* InViewportManager) const
{
const UDisplayClusterInFrustumFitCameraComponent& ConfigurationCameraComponent = InViewportManager ? GetConfigurationInFrustumFitCameraComponent(InViewportManager->GetConfiguration()) : *this;
// Only when this component is enabled should viewports be created for the entire cluster that accesses this component.
return ConfigurationCameraComponent.IsEnabled();
}
IDisplayClusterWarpPolicy* UDisplayClusterInFrustumFitCameraComponent::GetWarpPolicy(IDisplayClusterViewportManager* InViewportManager)
{
using namespace UE::DisplayClusterWarp::ViewPointComponent;
// We can ask for different types of warp policies, depending on the rules of the user settings
const FString NewWaprPolicyType = UE::DisplayClusterWarpStrings::warp::InFrustumFit;
// when returns different type, this will recreate warp policy instance
if (WarpPolicy.IsValid() && WarpPolicy->GetType() != NewWaprPolicyType)
{
WarpPolicy.Reset();
}
if (!WarpPolicy.IsValid())
{
WarpPolicy = ImplCreateWarpPolicy(NewWaprPolicyType, GetName());
}
return WarpPolicy.Get();
}
void UDisplayClusterInFrustumFitCameraComponent::OnRegister()
{
Super::OnRegister();
#if WITH_EDITOR
if (GIsEditor && !IsRunningCommandlet())
{
if (SpriteComponent)
{
SpriteComponent->SpriteInfo.Category = TEXT("NDisplayCameraViewOrigin");
SpriteComponent->SpriteInfo.DisplayName = NSLOCTEXT("DisplayClusterInFrustumFitCameraComponent", "DisplayClusterInFrustumFitCameraComponentSpriteInfo", "nDisplay InFrustumFit View Point");
}
}
RefreshVisualRepresentation();
#endif
}
#if WITH_EDITOR
bool UDisplayClusterInFrustumFitCameraComponent::CanEditChange(const FProperty* InProperty) const
{
// If other logic prevents editing, we want to respect that
bool bIsEditable = Super::CanEditChange(InProperty);
if (bIsEditable && InProperty)
{
// InFrustum projection requires external cinecamera
const FName PropertyName = InProperty->GetFName();
if (PropertyName == GET_MEMBER_NAME_CHECKED(UDisplayClusterCameraComponent, ICVFXCameraComponentName))
{
return !IsEnabled();
}
}
return bIsEditable;
}
void UDisplayClusterInFrustumFitCameraComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
if (PropertyName == GET_MEMBER_NAME_CHECKED(UDisplayClusterCameraComponent, TargetCameraType)
|| PropertyName == GET_MEMBER_NAME_CHECKED(UDisplayClusterInFrustumFitCameraComponent, bEnableCameraProjection))
{
if (IsEnabled() && TargetCameraType == EDisplayClusterTargetCameraType::ICVFXCameraComponent)
{
// When using projection, the internal target camera type cannot be used.
// We have to switch to the external target camera type.
TargetCameraType = EDisplayClusterTargetCameraType::None;
}
}
Super::PostEditChangeProperty(PropertyChangedEvent);
}
#endif