// Copyright Ngonart OU. All Rights Reserved. // UE5 Modular Game Framework — BPC_PlanarCapture (136) // The heart of the Planar Capture System. Attached to any actor that needs // a scene capture — mirrors, portals, monitors, horror surfaces. // // Manages USceneCaptureComponent2D lifetime, render target pool allocation, // camera transform computation per mode, oblique clip plane injection, // show/hide actor lists, quality tier application, frame ring buffer, // and MPC parameter pushes. #pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "Capture/PlanarCaptureCommon.h" #include "BPC_PlanarCapture.generated.h" // Forward declarations class USceneCaptureComponent2D; class UTextureRenderTarget2D; class UMaterialInstanceDynamic; class UMaterialParameterCollection; class ASS_PlanarCaptureManager; class ABP_PlanarCaptureActor; // ============================================================================ // Delegates // ============================================================================ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnCaptureQualityChanged, EPlanarCaptureQualityTier, OldTier, EPlanarCaptureQualityTier, NewTier); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCaptureInitialized, EPlanarCaptureInitResult, Result); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnCaptureRendered); /** * BPC_PlanarCapture — Core capture component for mirrors, portals, monitors, etc. * * Owns the USceneCaptureComponent2D lifecycle. All camera math, render target * management, and per-frame capture decisions happen here in C++ for performance. * Designer configuration flows through Blueprint children. * * Multiplayer: Capture is always local-only. Each client renders their own view. * No replication needed. This component only exists on clients. */ UCLASS(Blueprintable, ClassGroup = (Framework), meta = (BlueprintSpawnableComponent)) class PG_FRAMEWORK_API UBPC_PlanarCapture : public UActorComponent { GENERATED_BODY() public: UBPC_PlanarCapture(); // ======================================================================== // Lifecycle // ======================================================================== virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; // ======================================================================== // Configuration — Set in Blueprint Defaults // ======================================================================== /** What kind of surface this capture represents. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config") EPlanarCaptureMode CaptureMode = EPlanarCaptureMode::Mirror; /** Quality profiles per tier (0=Low, 1=Medium, 2=High, 3=Hero). Index maps to EPlanarCaptureQualityTier. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config") TArray QualityProfiles; /** FOV for the capture camera. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config") float CaptureFOV = 90.0f; /** Maximum view distance for the capture (0 = unlimited). */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capture|Config") float MaxViewDistance = 5000.0f; // ======================================================================== // Portal Configuration // ======================================================================== /** For Portal mode: the linked target surface actor. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Portal") TSoftObjectPtr LinkedTargetSurface; // ======================================================================== // Monitor Configuration // ======================================================================== /** For Monitor mode: a fixed camera actor to capture from. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Monitor") TSoftObjectPtr FixedCameraActor; // ======================================================================== // Actor Lists // ======================================================================== /** Actors to show exclusively in the capture (empty = show all). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|ActorLists") TArray ShowOnlyActors; /** Actors to hide from the capture. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|ActorLists") TArray HiddenActors; // ======================================================================== // Horror Configuration // ======================================================================== /** Actor to swap into the ShowOnly list during wrong-reflection events. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Horror") TSoftObjectPtr WrongReflectionActor; /** Mesh component of the surface plane (for clip plane calculation). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capture|Config") TSoftObjectPtr SurfaceMeshComponent; // ======================================================================== // Runtime State (Read-Only) // ======================================================================== /** Current assigned quality tier (set by SS_PlanarCaptureManager). */ UPROPERTY(BlueprintReadOnly, Category = "Capture|Runtime") EPlanarCaptureQualityTier CurrentQualityTier = EPlanarCaptureQualityTier::Off; /** Is this capture currently active (capturing frames)? */ UPROPERTY(BlueprintReadOnly, Category = "Capture|Runtime") bool bIsCapturing = false; /** The render target this capture writes to. */ UPROPERTY(BlueprintReadOnly, Category = "Capture|Runtime") TObjectPtr CaptureRenderTarget; // ======================================================================== // Public API — BlueprintCallable // ======================================================================== /** * Initialize the capture component. Allocates render target, creates and * configures the USceneCaptureComponent2D. Called by the owning actor on BeginPlay. */ UFUNCTION(BlueprintCallable, Category = "Capture") EPlanarCaptureInitResult InitializeCapture(); /** * Shut down the capture, release render target back to pool, destroy SceneCaptureComponent2D. */ UFUNCTION(BlueprintCallable, Category = "Capture") void ShutdownCapture(); /** * Apply a quality tier profile immediately. Called by SS_PlanarCaptureManager. */ UFUNCTION(BlueprintCallable, Category = "Capture") void ApplyQualityTier(EPlanarCaptureQualityTier Tier); /** * Trigger a single capture frame immediately (bypasses tick interval). */ UFUNCTION(BlueprintCallable, Category = "Capture") void CaptureNow(); /** * Swap the ShowOnly actor list to the wrong-reflection actor (horror mode). * Original list is preserved and restored on DeactivateHorrorReflection(). */ UFUNCTION(BlueprintCallable, Category = "Capture|Horror") void ActivateHorrorReflection(); /** * Restore the original ShowOnly actor list after a horror event. */ UFUNCTION(BlueprintCallable, Category = "Capture|Horror") void DeactivateHorrorReflection(); /** * Push a frame from the ring buffer into the render target for delayed reflection (horror lag). */ UFUNCTION(BlueprintCallable, Category = "Capture|Horror") void PushDelayedFrame(); /** * Set a scripted priority override (0.0 to 1.0). Higher values force higher quality tier. * Example: a scare event elevates a specific mirror to Hero tier. */ UFUNCTION(BlueprintCallable, Category = "Capture") void SetScriptedPriority(float Priority); /** * Push all Material Parameter Collection values for this surface. * Called every frame when capturing, or on event trigger for horror params. */ UFUNCTION(BlueprintCallable, Category = "Capture|Material") void PushMPCParameters(UMaterialParameterCollection* MPC); // ======================================================================== // Compute — BlueprintPure // ======================================================================== /** Compute the capture camera transform for the current mode. */ UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture") FTransform ComputeCaptureCameraTransform(const FTransform& ViewerCameraTransform) const; /** Get the current composite quality score. */ UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Capture") FPlanarCaptureScore GetCurrentScore() const; // ======================================================================== // Event Dispatchers // ======================================================================== UPROPERTY(BlueprintAssignable, Category = "Capture|Events") FOnCaptureQualityChanged OnCaptureQualityChanged; UPROPERTY(BlueprintAssignable, Category = "Capture|Events") FOnCaptureInitialized OnCaptureInitialized; UPROPERTY(BlueprintAssignable, Category = "Capture|Events") FOnCaptureRendered OnCaptureRendered; protected: // ======================================================================== // Internal State // ======================================================================== /** The actual UE5 SceneCaptureComponent2D — created at runtime. */ UPROPERTY() TObjectPtr SceneCapture; /** Cached reference to the manager subsystem. */ UPROPERTY() TObjectPtr CachedManager; /** Cached reference to the owning actor. */ UPROPERTY() TObjectPtr CachedOwningActor; /** Time accumulator for capture interval throttling. */ float TimeSinceLastCapture = 0.0f; /** Current quality profile (cached from QualityProfiles[Tier]). */ FPlanarCaptureQualityProfile ActiveProfile; /** Scripted priority override (0.0 to 1.0). */ float ScriptedPriorityOverride = 0.0f; /** Ring buffer of render targets for delayed reflection (horror mode). */ UPROPERTY() TArray> FrameRingBuffer; /** Current write index into the frame ring buffer. */ int32 RingBufferWriteIndex = 0; /** Saved ShowOnly list before horror swap. */ TArray> SavedShowOnlyActors; // ======================================================================== // Internal Methods // ======================================================================== /** Create and configure the USceneCaptureComponent2D. */ void CreateSceneCaptureComponent(); /** Apply show flags from the active quality profile to the SceneCapture. */ void ApplyShowFlags(); /** Update the ShowOnly and Hidden actor lists on the SceneCapture. */ void UpdateActorLists(); /** Resolve soft references on initialization. */ void ResolveSoftReferences(); /** Compute the surface plane in world space for clip plane and mirror math. */ FPlane GetSurfacePlane() const; };