[UE4] CineCameraActor

likefeb16220·2022년 4월 1일
0

CineCameraActor ??

CameraActor에 실제 카메라와 관련된 세팅이 추가된 Actor. (ACameraActor를 상속받는다.)
CameraActor는 모니터 기능, CineCameraActor는 영화 촬영용이라고 생각하면 된다.
(Cinema : 영화, 영화 제작, 영화관)
CineCameraActor는 영화 촬영 역할에 걸맞게 Actor를 트래킹하는 기능이 있다.

Editor

CineCameraActor와 CameraActor가 Editor의 Detail 창에서 표시되는 내용

CineCameraActor의 경우 카메라 세팅 항목이 추가되어 있다

참고자료

Unreal Engine Document

https://docs.unrealengine.com/4.27/ko/AnimatingObjects/Sequencer/Cameras/CineCameraActors/
https://docs.unrealengine.com/4.27/en-US/AnimatingObjects/Sequencer/Cameras/CineCameraActors/

코드 원본 (Ver 4.27.2)

CameraActor.h


// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "GameFramework/Actor.h"
#include "Engine/Scene.h"

#include "CameraActor.generated.h"

class UCameraAnim;

/** 
 * A CameraActor is a camera viewpoint that can be placed in a level.
 */
UCLASS(ClassGroup=Common, hideCategories=(Input, Rendering), showcategories=("Input|MouseInput", "Input|TouchInput"), Blueprintable)
class ENGINE_API ACameraActor : public AActor
{
	GENERATED_UCLASS_BODY()

private:

	/** Specifies which player controller, if any, should automatically use this Camera when the controller is active. */
	UPROPERTY(Category="AutoPlayerActivation", EditAnywhere)
	TEnumAsByte<EAutoReceiveInput::Type> AutoActivateForPlayer;

private:

	/** The camera component for this camera */
	UPROPERTY(Category = CameraActor, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* CameraComponent;

	UPROPERTY(Category = CameraActor, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	class USceneComponent* SceneComponent;
public:

	/** If this CameraActor is being used to preview a CameraAnim in the editor, this is the anim being previewed. */
	TWeakObjectPtr<class UCameraAnim> PreviewedCameraAnim;

	/** Returns index of the player for whom we auto-activate, or INDEX_NONE (-1) if disabled. */
	UFUNCTION(BlueprintCallable, Category="AutoPlayerActivation")
	int32 GetAutoActivatePlayerIndex() const;

private:

	UPROPERTY()
	uint32 bConstrainAspectRatio_DEPRECATED:1;

	UPROPERTY()
	float AspectRatio_DEPRECATED;

	UPROPERTY()
	float FOVAngle_DEPRECATED;

	UPROPERTY()
	float PostProcessBlendWeight_DEPRECATED;

	UPROPERTY()
	struct FPostProcessSettings PostProcessSettings_DEPRECATED;

public:
	//~ Begin UObject Interface
	virtual void Serialize(FArchive& Ar) override;

#if WITH_EDITOR
	virtual void PostLoadSubobjects(FObjectInstancingGraph* OuterInstanceGraph) override;

	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif

	virtual class USceneComponent* GetDefaultAttachComponent() const override;
	//~ End UObject Interface

protected:
	//~ Begin AActor Interface
	virtual void BeginPlay() override;
	//~ End AActor Interface

public:
	/** Returns CameraComponent subobject **/
	class UCameraComponent* GetCameraComponent() const { return CameraComponent; }

	/** 
	 * Called to notify that this camera was cut to, so it can update things like interpolation if necessary.
	 * Typically called by the camera component.
	 */
	virtual void NotifyCameraCut() {};

};

CameraActor.cpp


// Copyright Epic Games, Inc. All Rights Reserved.

#include "Camera/CameraActor.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"
#include "Camera/CameraComponent.h"
#include "Camera/CameraAnim.h"

#define LOCTEXT_NAMESPACE "CameraActor"

//////////////////////////////////////////////////////////////////////////
// ACameraActor

ACameraActor::ACameraActor(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));

	// Make the scene component the root component
	RootComponent = SceneComponent;
	
	// Setup camera defaults
	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
	CameraComponent->FieldOfView = 90.0f;
	CameraComponent->bConstrainAspectRatio = true;
	CameraComponent->AspectRatio = 1.777778f;
	CameraComponent->PostProcessBlendWeight = 1.0f;
	
	CameraComponent->SetupAttachment(SceneComponent);

	// Initialize deprecated properties (needed for backwards compatibility due to delta serialization)
	FOVAngle_DEPRECATED = 90.0f;
	bConstrainAspectRatio_DEPRECATED = true;
	AspectRatio_DEPRECATED = 1.777778f;
	PostProcessBlendWeight_DEPRECATED = 1.0f;
	// End of deprecated property initialization
}

void ACameraActor::Serialize(FArchive& Ar)
{
	Super::Serialize(Ar);

	if ((Ar.UE4Ver() < VER_UE4_CAMERA_ACTOR_USING_CAMERA_COMPONENT) && Ar.IsLoading())
	{
		CameraComponent->bConstrainAspectRatio = bConstrainAspectRatio_DEPRECATED;
		CameraComponent->ProjectionMode = ECameraProjectionMode::Perspective;
		CameraComponent->AspectRatio = AspectRatio_DEPRECATED;
		CameraComponent->FieldOfView = FOVAngle_DEPRECATED;
		CameraComponent->PostProcessBlendWeight = PostProcessBlendWeight_DEPRECATED;
		CameraComponent->PostProcessSettings = PostProcessSettings_DEPRECATED;
	}
}

#if WITH_EDITOR
void ACameraActor::PostLoadSubobjects(FObjectInstancingGraph* OuterInstanceGraph)
{
	USceneComponent* OldRoot = RootComponent;
	USceneComponent* OldAttachParent = OldRoot->GetAttachParent();
	const FName OldSocketName = OldRoot->GetAttachSocketName();

	Super::PostLoadSubobjects(OuterInstanceGraph);
	
	if (GetLinkerUE4Version() < VER_UE4_CAMERA_ACTOR_USING_CAMERA_COMPONENT)
	{
		CameraComponent->SetupAttachment(OldAttachParent, OldSocketName);
		OldRoot->SetupAttachment(nullptr);
	}

	if (GetLinkerUE4Version() < VER_UE4_CAMERA_COMPONENT_ATTACH_TO_ROOT)
	{
		RootComponent = SceneComponent;
		if (OldAttachParent != SceneComponent)
		{
			CameraComponent->SetupAttachment(RootComponent);
			RootComponent->SetupAttachment(OldAttachParent, OldSocketName);
		}
	}
}

void ACameraActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	if (PreviewedCameraAnim.IsValid() && CameraComponent)
	{
		PreviewedCameraAnim->BaseFOV = CameraComponent->FieldOfView;
		PreviewedCameraAnim->BasePostProcessSettings = CameraComponent->PostProcessSettings;
		PreviewedCameraAnim->BasePostProcessBlendWeight = CameraComponent->PostProcessBlendWeight;
	}
}

#endif

USceneComponent* ACameraActor::GetDefaultAttachComponent() const
{
	return CameraComponent;
}

int32 ACameraActor::GetAutoActivatePlayerIndex() const
{
	if (AutoActivateForPlayer != EAutoReceiveInput::Disabled)
	{
		const int32 PlayerIndex = int32(AutoActivateForPlayer.GetValue()) - 1;
		return PlayerIndex;
	}
	else
	{
		return INDEX_NONE;
	}
}

void ACameraActor::BeginPlay()
{
	if (AutoActivateForPlayer != EAutoReceiveInput::Disabled && GetNetMode() != NM_Client)
	{
		const int32 PlayerIndex = GetAutoActivatePlayerIndex();
		
		// Always put it in the pool of available auto-activate cameras.
		GetWorld()->RegisterAutoActivateCamera(this, PlayerIndex);

		// If we find a matching PC, bind to it immediately.
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, PlayerIndex);
		if (PC)
		{
			PC->SetViewTarget(this);
		}
	}

	Super::BeginPlay();
}

#undef LOCTEXT_NAMESPACE

CineCameraActor.h


// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Camera/CameraActor.h"

#include "CineCameraActor.generated.h"

class UCineCameraComponent;

/** Settings to control the camera's lookat feature */
USTRUCT(BlueprintType)
struct FCameraLookatTrackingSettings
{
	GENERATED_USTRUCT_BODY()

	FCameraLookatTrackingSettings()
		: bEnableLookAtTracking(false)
		, bDrawDebugLookAtTrackingPosition(false)
		, LookAtTrackingInterpSpeed(0.f)
		, LastLookatTrackingRotation(FRotator::ZeroRotator)
		, RelativeOffset(FVector::ZeroVector)
		, bAllowRoll(false)
	{
	}

	/** True to enable lookat tracking, false otherwise. */
	UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "LookAt")
	uint8 bEnableLookAtTracking : 1;

	/** True to draw a debug representation of the lookat location */
	UPROPERTY(Transient, EditAnywhere, BlueprintReadWrite, Category = "LookAt")
	uint8 bDrawDebugLookAtTrackingPosition : 1;

	/** Controls degree of smoothing. 0.f for no smoothing, higher numbers for faster/tighter tracking. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LookAt")
	float LookAtTrackingInterpSpeed;

	/** Last known lookat tracking rotation (used during interpolation) */
	FRotator LastLookatTrackingRotation;

	/** If set, camera will track this actor's location */
	UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "LookAt")
	TSoftObjectPtr<AActor> ActorToTrack;

	/** Offset from actor position to look at. Relative to actor if tracking an actor, relative to world otherwise. */
	UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "LookAt")
	FVector RelativeOffset;

	/** True to allow user-defined roll, false otherwise. */
	UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "LookAt")
	uint8 bAllowRoll : 1;
};

/** 
 * A CineCameraActor is a CameraActor specialized to work like a cinematic camera.
 */
UCLASS(ClassGroup = Common, hideCategories = (Input, Rendering, AutoPlayerActivation), showcategories = ("Input|MouseInput", "Input|TouchInput"), Blueprintable)
class CINEMATICCAMERA_API ACineCameraActor : public ACameraActor
{
	GENERATED_BODY()

public:
	// Ctor
	ACineCameraActor(const FObjectInitializer& ObjectInitializer);

	virtual void Tick(float DeltaTime) override;
	virtual bool ShouldTickIfViewportsOnly() const override;
	virtual void PostInitializeComponents() override;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Current Camera Settings")
	FCameraLookatTrackingSettings LookatTrackingSettings;

	/** Returns the CineCameraComponent of this CineCamera */
	UFUNCTION(BlueprintCallable, Category="Camera")
	UCineCameraComponent* GetCineCameraComponent() const { return CineCameraComponent; }

protected:
	/** Set to true to skip any interpolations on the next update. Resets to false automatically. */
	uint8 bResetInterplation : 1;

	FVector GetLookatLocation() const;

	virtual void NotifyCameraCut() override;

	bool ShouldTickForTracking() const;

private:
	/** Returns CineCameraComponent subobject **/
	class UCineCameraComponent* CineCameraComponent;
};

CineCameraActor.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "CineCameraActor.h"
#include "DrawDebugHelpers.h"
#include "CineCameraComponent.h"

#define LOCTEXT_NAMESPACE "CineCameraActor"

//////////////////////////////////////////////////////////////////////////
// ACameraActor

ACineCameraActor::ACineCameraActor(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer
			.SetDefaultSubobjectClass<UCineCameraComponent>(TEXT("CameraComponent"))
	)
{
	CineCameraComponent = Cast<UCineCameraComponent>(GetCameraComponent());

	PrimaryActorTick.bCanEverTick = true;
	SetActorTickEnabled(true);
}

void ACineCameraActor::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	LookatTrackingSettings.LastLookatTrackingRotation = GetActorRotation();
}

bool ACineCameraActor::ShouldTickIfViewportsOnly() const
{
	return true;
}

FVector ACineCameraActor::GetLookatLocation() const
{
	FVector FinalLookat;
	if (AActor* ActorToTrack = LookatTrackingSettings.ActorToTrack.Get())
	{
		FTransform const BaseTransform = ActorToTrack->GetActorTransform();
		FinalLookat = BaseTransform.TransformPosition(LookatTrackingSettings.RelativeOffset);
	}
	else
	{
		FinalLookat = LookatTrackingSettings.RelativeOffset;
	}

	return FinalLookat;
}

static const FColor DebugLookatTrackingPointSolidColor(200, 200, 32, 128);		// yellow
static const FColor DebugLookatTrackingPointOutlineColor = FColor::Black;

void ACineCameraActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (GetCameraComponent() && ShouldTickForTracking())
	{
		if (LookatTrackingSettings.bEnableLookAtTracking)
		{
			// do the lookat tracking
			// #note this will turn the whole actor, which assumes the cameracomponent's transform is the same as the root component
			// more complex component hierarchies will require different handling here
			FVector const LookatLoc = GetLookatLocation();
			FVector const ToLookat = LookatLoc - GetActorLocation();
			FRotator FinalRot = 
				bResetInterplation
				? ToLookat.Rotation()
				: FMath::RInterpTo(LookatTrackingSettings.LastLookatTrackingRotation, ToLookat.Rotation(), DeltaTime, LookatTrackingSettings.LookAtTrackingInterpSpeed);

			if (LookatTrackingSettings.bAllowRoll)
			{
				FinalRot.Roll = GetActorRotation().Roll;
			}

			SetActorRotation(FinalRot);

			// we store this ourselves in case other systems try to change our rotation, and end fighting the interpolation
			LookatTrackingSettings.LastLookatTrackingRotation = FinalRot;

#if ENABLE_DRAW_DEBUG
			if (LookatTrackingSettings.bDrawDebugLookAtTrackingPosition)
			{
				::DrawDebugSolidBox(GetWorld(), LookatLoc, FVector(12.f), DebugLookatTrackingPointSolidColor);
				::DrawDebugBox(GetWorld(), LookatLoc, FVector(12.f), DebugLookatTrackingPointOutlineColor);
			}
#endif // ENABLE_DRAW_DEBUG
		}
	}

	bResetInterplation = false;
}


void ACineCameraActor::NotifyCameraCut()
{
	Super::NotifyCameraCut();
	
	bResetInterplation = true;
}

bool ACineCameraActor::ShouldTickForTracking() const
{
	bool bShouldTickForTracking = 
		LookatTrackingSettings.bEnableLookAtTracking || 
		CineCameraComponent->FocusSettings.TrackingFocusSettings.bDrawDebugTrackingFocusPoint;

#if WITH_EDITORONLY_DATA
	if (CineCameraComponent->FocusSettings.bDrawDebugFocusPlane)
	{
		bShouldTickForTracking = true;
	}
#endif // WITH_EDITORONLY_DATA

	return bShouldTickForTracking;
}


#undef LOCTEXT_NAMESPACE

0개의 댓글