/*
update target 分三个种类
第一类 就是CameraActor
直接计算的是CamActor->GetCameraComponent()->GetCameraView(DeltaTime, OutVT.POV);
第二类是设置了CameraStyle 为某个值的,这个时候不管target是什么类型都会按照这个值的规则来计算
第三类就是其他的任何actor,计算用的是
UpdateViewTargetInternal(OutVT, DeltaTime);
*/
void APlayerCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)
{
// Don't update outgoing viewtarget during an interpolation
if ((PendingViewTarget.Target != NULL) && BlendParams.bLockOutgoing && OutVT.Equal(ViewTarget))
{
return;
}
// Store previous POV, in case we need it later
FMinimalViewInfo OrigPOV = OutVT.POV;
// Reset the view target POV fully
static const FMinimalViewInfo DefaultViewInfo;
OutVT.POV = DefaultViewInfo;
OutVT.POV.FOV = DefaultFOV;
OutVT.POV.OrthoWidth = DefaultOrthoWidth;
OutVT.POV.AspectRatio = DefaultAspectRatio;
OutVT.POV.bConstrainAspectRatio = bDefaultConstrainAspectRatio;
OutVT.POV.ProjectionMode = bIsOrthographic ? ECameraProjectionMode::Orthographic : ECameraProjectionMode::Perspective;
OutVT.POV.PostProcessBlendWeight = 1.0f;
bool bDoNotApplyModifiers = false;
if (ACameraActor* CamActor = Cast<ACameraActor>(OutVT.Target))
{
// Viewing through a camera actor.
CamActor->GetCameraComponent()->GetCameraView(DeltaTime, OutVT.POV);
}
else
{
static const FName NAME_Fixed = FName(TEXT("Fixed"));
static const FName NAME_ThirdPerson = FName(TEXT("ThirdPerson"));
static const FName NAME_FreeCam = FName(TEXT("FreeCam"));
static const FName NAME_FreeCam_Default = FName(TEXT("FreeCam_Default"));
static const FName NAME_FirstPerson = FName(TEXT("FirstPerson"));
if (CameraStyle == NAME_Fixed)
{
// do not update, keep previous camera position by restoring
// saved POV, in case CalcCamera changes it but still returns false
OutVT.POV = OrigPOV;
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
}
else if (CameraStyle == NAME_ThirdPerson || CameraStyle == NAME_FreeCam || CameraStyle == NAME_FreeCam_Default)
{
// Simple third person view implementation
FVector Loc = OutVT.Target->GetActorLocation();
FRotator Rotator = OutVT.Target->GetActorRotation();
if (OutVT.Target == PCOwner)
{
Loc = PCOwner->GetFocalLocation();
}
// Take into account Mesh Translation so it takes into account the PostProcessing we do there.
// @fixme, can crash in certain BP cases where default mesh is null
// APawn* TPawn = Cast<APawn>(OutVT.Target);
// if ((TPawn != NULL) && (TPawn->Mesh != NULL))
// {
// Loc += FQuatRotationMatrix(OutVT.Target->GetActorQuat()).TransformVector(TPawn->Mesh->RelativeLocation - GetDefault<APawn>(TPawn->GetClass())->Mesh->RelativeLocation);
// }
//OutVT.Target.GetActorEyesViewPoint(Loc, Rot);
if( CameraStyle == NAME_FreeCam || CameraStyle == NAME_FreeCam_Default )
{
Rotator = PCOwner->GetControlRotation();
}
FVector Pos = Loc + ViewTargetOffset + FRotationMatrix(Rotator).TransformVector(FreeCamOffset) - Rotator.Vector() * FreeCamDistance;
FCollisionQueryParams BoxParams(SCENE_QUERY_STAT(FreeCam), false, this);
BoxParams.AddIgnoredActor(OutVT.Target);
FHitResult Result;
GetWorld()->SweepSingleByChannel(Result, Loc, Pos, FQuat::Identity, ECC_Camera, FCollisionShape::MakeBox(FVector(12.f)), BoxParams);
OutVT.POV.Location = !Result.bBlockingHit ? Pos : Result.Location;
OutVT.POV.Rotation = Rotator;
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
}
else if (CameraStyle == NAME_FirstPerson)
{
// Simple first person, view through viewtarget's 'eyes'
OutVT.Target->GetActorEyesViewPoint(OutVT.POV.Location, OutVT.POV.Rotation);
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
}
else
{
UpdateViewTargetInternal(OutVT, DeltaTime);
}
}
if (!bDoNotApplyModifiers || bAlwaysApplyModifiers)
{
// Apply camera modifiers at the end (view shakes for example)
ApplyCameraModifiers(DeltaTime, OutVT.POV);
}
// Synchronize the actor with the view target results
SetActorLocationAndRotation(OutVT.POV.Location, OutVT.POV.Rotation, false);
UpdateCameraLensEffects(OutVT);
}
一般都会走到第三类target里面
/*
要么被蓝图函数拦截,这个蓝图是CameraManager的蓝图函数
要么就走到actor的CalcCamera里面
OutVT.Target->CalcCamera(DeltaTime, OutVT.POV);
*/
void APlayerCameraManager::UpdateViewTargetInternal(FTViewTarget& OutVT, float DeltaTime)
{
if (OutVT.Target)
{
FVector OutLocation;
FRotator OutRotation;
float OutFOV;
if (BlueprintUpdateCamera(OutVT.Target, OutLocation, OutRotation, OutFOV))
{
OutVT.POV.Location = OutLocation;
OutVT.POV.Rotation = OutRotation;
OutVT.POV.FOV = OutFOV;
}
else
{
OutVT.Target->CalcCamera(DeltaTime, OutVT.POV);
}
}
}
/*
actor内部的计算
先找CameraComponent,走CameraComponent->GetCameraView(DeltaTime, OutResult);
没有的话就走
GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
*/
void AActor::CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult)
{
if (bFindCameraComponentWhenViewTarget)
{
// Look for the first active camera component and use that for the view
TInlineComponentArray<UCameraComponent*> Cameras;
GetComponents(/*out*/ Cameras);
for (UCameraComponent* CameraComponent : Cameras)
{
if (CameraComponent->IsActive())
{
CameraComponent->GetCameraView(DeltaTime, OutResult);
return;
}
}
}
GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
}
/*
虚函数可以重载,决定一个actor的视角loc和rot
*/
void AActor::GetActorEyesViewPoint( FVector& OutLocation, FRotator& OutRotation ) const
{
OutLocation = GetActorLocation();
OutRotation = GetActorRotation();
}
---------------------------------------------------------------------------------------------
一个标准的摄像机旋转系统如下效果
他的配置是什么
1、character的
2、character上添加
3、SpringArm
4、camera com
5、input和add controller yaw等相关联
那么上述的数据是怎么传递的呢,就是说怎么我旋转了鼠标偏偏就能影响摄像机呢
先从add controller yaw入手
void APawn::AddControllerYawInput(float Val)
{
if (Val != 0.f && Controller && Controller->IsLocalPlayerController())
{
APlayerController* const PC = CastChecked<APlayerController>(Controller);
PC->AddYawInput(Val);
}
}
void APlayerController::AddYawInput(float Val)
{
RotationInput.Yaw += !IsLookInputIgnored() ? Val * (GetDefault<UInputSettings>()->bEnableLegacyInputScales ? InputYawScale_DEPRECATED : 1.0f) : 0.0f;
}
void APlayerController::UpdateRotation( float DeltaTime )
{
// Calculate Delta to be applied on ViewRotation
FRotator DeltaRot(RotationInput);
FRotator ViewRotation = GetControlRotation();
if (PlayerCameraManager)
{
//这里虽然拐进了camera manager类但是内部却没有对camera有任何改变
PlayerCameraManager->ProcessViewRotation(DeltaTime, ViewRotation, DeltaRot);
}
AActor* ViewTarget = GetViewTarget();
if (!PlayerCameraManager || !ViewTarget || !ViewTarget->HasActiveCameraComponent() || ViewTarget->HasActivePawnControlCameraComponent())
{
if (IsLocalPlayerController() && GEngine->XRSystem.IsValid() && GetWorld() != nullptr && GEngine->XRSystem->IsHeadTrackingAllowedForWorld(*GetWorld()))
{
auto XRCamera = GEngine->XRSystem->GetXRCamera();
if (XRCamera.IsValid())
{
XRCamera->ApplyHMDRotation(this, ViewRotation);
}
}
}
//直接影响controller的rotation
SetControlRotation(ViewRotation);
//对pawn的rotation也会有影响
APawn* const P = GetPawnOrSpectator();
if (P)
{
P->FaceRotation(ViewRotation, DeltaTime);
}
}
void APawn::FaceRotation(FRotator NewControlRotation, float DeltaTime)
{
// Only if we actually are going to use any component of rotation.
//这几个变量很熟悉吧
if (bUseControllerRotationPitch || bUseControllerRotationYaw || bUseControllerRotationRoll)
{
const FRotator CurrentRotation = GetActorRotation();
if (!bUseControllerRotationPitch)
{
NewControlRotation.Pitch = CurrentRotation.Pitch;
}
if (!bUseControllerRotationYaw)
{
NewControlRotation.Yaw = CurrentRotation.Yaw;
}
if (!bUseControllerRotationRoll)
{
NewControlRotation.Roll = CurrentRotation.Roll;
}
#if ENABLE_NAN_DIAGNOSTIC
if (NewControlRotation.ContainsNaN())
{
logOrEnsureNanError(TEXT("APawn::FaceRotation about to apply NaN-containing rotation to actor! New:(%s), Current:(%s)"), *NewControlRotation.ToString(), *CurrentRotation.ToString());
}
#endif
SetActorRotation(NewControlRotation);
}
}
结论最终改变的就是controller的rotation和pawn的rotation(有条件的)
然后在spring arm中
FRotator USpringArmComponent::GetTargetRotation() const
{
FRotator DesiredRot = GetDesiredRotation();
//这里我们设置为true了
if (bUsePawnControlRotation)
{
if (APawn* OwningPawn = Cast<APawn>(GetOwner()))
{
const FRotator PawnViewRotation = OwningPawn->GetViewRotation();
if (DesiredRot != PawnViewRotation)
{
DesiredRot = PawnViewRotation;
}
}
}
// If inheriting rotation, check options for which components to inherit
if (!IsUsingAbsoluteRotation())
{
const FRotator LocalRelativeRotation = GetRelativeRotation();
if (!bInheritPitch)
{
DesiredRot.Pitch = LocalRelativeRotation.Pitch;
}
if (!bInheritYaw)
{
DesiredRot.Yaw = LocalRelativeRotation.Yaw;
}
if (!bInheritRoll)
{
DesiredRot.Roll = LocalRelativeRotation.Roll;
}
}
return DesiredRot;
}
FRotator APawn::GetViewRotation() const
{
//取得就是controller的rotator
if (Controller != nullptr)
{
return Controller->GetControlRotation();
}
else if (GetLocalRole() < ROLE_Authority)
{
// check if being spectated
for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator)
{
APlayerController* PlayerController = Iterator->Get();
if (PlayerController &&
PlayerController->PlayerCameraManager &&
PlayerController->PlayerCameraManager->GetViewTargetPawn() == this)
{
return PlayerController->BlendedTargetViewRotation;
}
}
}
return GetActorRotation();
}
//这一大串代码的目的无非就是,spingarm为了和controller的rotation一样的同时,为了保证始终面向
//角色,也就是lookat 角色,为了这个效果,从而反推出来springarm要移动多少位置,才能达到这个目的
//最终是根据desiredrot和springarm length和 要lookat pawn算出location
void USpringArmComponent::UpdateDesiredArmLocation(bool bDoTrace, bool bDoLocationLag, bool bDoRotationLag, float DeltaTime)
{
FRotator DesiredRot = GetTargetRotation();
// If our viewtarget is simulating using physics, we may need to clamp deltatime
if (bClampToMaxPhysicsDeltaTime)
{
// Use the same max timestep cap as the physics system to avoid camera jitter when the viewtarget simulates less time than the camera
DeltaTime = FMath::Min(DeltaTime, UPhysicsSettings::Get()->MaxPhysicsDeltaTime);
}
// Apply 'lag' to rotation if desired
if(bDoRotationLag)
{
if (bUseCameraLagSubstepping && DeltaTime > CameraLagMaxTimeStep && CameraRotationLagSpeed > 0.f)
{
const FRotator ArmRotStep = (DesiredRot - PreviousDesiredRot).GetNormalized() * (1.f / DeltaTime);
FRotator LerpTarget = PreviousDesiredRot;
float RemainingTime = DeltaTime;
while (RemainingTime > UE_KINDA_SMALL_NUMBER)
{
const float LerpAmount = FMath::Min(CameraLagMaxTimeStep, RemainingTime);
LerpTarget += ArmRotStep * LerpAmount;
RemainingTime -= LerpAmount;
DesiredRot = FRotator(FMath::QInterpTo(FQuat(PreviousDesiredRot), FQuat(LerpTarget), LerpAmount, CameraRotationLagSpeed));
PreviousDesiredRot = DesiredRot;
}
}
else
{
DesiredRot = FRotator(FMath::QInterpTo(FQuat(PreviousDesiredRot), FQuat(DesiredRot), DeltaTime, CameraRotationLagSpeed));
}
}
PreviousDesiredRot = DesiredRot;
// Get the spring arm 'origin', the target we want to look at
FVector ArmOrigin = GetComponentLocation() + TargetOffset;
// We lag the target, not the actual camera position, so rotating the camera around does not have lag
FVector DesiredLoc = ArmOrigin;
if (bDoLocationLag)
{
if (bUseCameraLagSubstepping && DeltaTime > CameraLagMaxTimeStep && CameraLagSpeed > 0.f)
{
const FVector ArmMovementStep = (DesiredLoc - PreviousDesiredLoc) * (1.f / DeltaTime);
FVector LerpTarget = PreviousDesiredLoc;
float RemainingTime = DeltaTime;
while (RemainingTime > UE_KINDA_SMALL_NUMBER)
{
const float LerpAmount = FMath::Min(CameraLagMaxTimeStep, RemainingTime);
LerpTarget += ArmMovementStep * LerpAmount;
RemainingTime -= LerpAmount;
DesiredLoc = FMath::VInterpTo(PreviousDesiredLoc, LerpTarget, LerpAmount, CameraLagSpeed);
PreviousDesiredLoc = DesiredLoc;
}
}
else
{
DesiredLoc = FMath::VInterpTo(PreviousDesiredLoc, DesiredLoc, DeltaTime, CameraLagSpeed);
}
// Clamp distance if requested
bool bClampedDist = false;
if (CameraLagMaxDistance > 0.f)
{
const FVector FromOrigin = DesiredLoc - ArmOrigin;
if (FromOrigin.SizeSquared() > FMath::Square(CameraLagMaxDistance))
{
DesiredLoc = ArmOrigin + FromOrigin.GetClampedToMaxSize(CameraLagMaxDistance);
bClampedDist = true;
}
}
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (bDrawDebugLagMarkers)
{
DrawDebugSphere(GetWorld(), ArmOrigin, 5.f, 8, FColor::Green);
DrawDebugSphere(GetWorld(), DesiredLoc, 5.f, 8, FColor::Yellow);
const FVector ToOrigin = ArmOrigin - DesiredLoc;
DrawDebugDirectionalArrow(GetWorld(), DesiredLoc, DesiredLoc + ToOrigin * 0.5f, 7.5f, bClampedDist ? FColor::Red : FColor::Green);
DrawDebugDirectionalArrow(GetWorld(), DesiredLoc + ToOrigin * 0.5f, ArmOrigin, 7.5f, bClampedDist ? FColor::Red : FColor::Green);
}
#endif
}
PreviousArmOrigin = ArmOrigin;
PreviousDesiredLoc = DesiredLoc;
// Now offset camera position back along our rotation
DesiredLoc -= DesiredRot.Vector() * TargetArmLength;
// Add socket offset in local space
DesiredLoc += FRotationMatrix(DesiredRot).TransformVector(SocketOffset);
// Do a sweep to ensure we are not penetrating the world
FVector ResultLoc;
if (bDoTrace && (TargetArmLength != 0.0f))
{
bIsCameraFixed = true;
FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(SpringArm), false, GetOwner());
FHitResult Result;
GetWorld()->SweepSingleByChannel(Result, ArmOrigin, DesiredLoc, FQuat::Identity, ProbeChannel, FCollisionShape::MakeSphere(ProbeSize), QueryParams);
UnfixedCameraPosition = DesiredLoc;
ResultLoc = BlendLocations(DesiredLoc, Result.Location, Result.bBlockingHit, DeltaTime);
if (ResultLoc == DesiredLoc)
{
bIsCameraFixed = false;
}
}
else
{
ResultLoc = DesiredLoc;
bIsCameraFixed = false;
UnfixedCameraPosition = ResultLoc;
}
// Form a transform for new world transform for camera
FTransform WorldCamTM(DesiredRot, ResultLoc);
// Convert to relative to component
FTransform RelCamTM = WorldCamTM.GetRelativeTransform(GetComponentTransform());
// Update socket location/rotation
RelativeSocketLocation = RelCamTM.GetLocation();
RelativeSocketRotation = RelCamTM.GetRotation();
UpdateChildTransforms();
}
-------------------------------------------------------------------------------------------------
manager只是负责切换viewtarge
可以通过springarm管理camera的朝向和位置,包括柔性的运动
也可以通过重写
actor 的calecamera
或者 cameracomponent的GetCameraView来重写逻辑
void AActor::CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult)
{
if (bFindCameraComponentWhenViewTarget)
{
// Look for the first active camera component and use that for the view
TInlineComponentArray<UCameraComponent*> Cameras;
GetComponents(/*out*/ Cameras);
for (UCameraComponent* CameraComponent : Cameras)
{
if (CameraComponent->IsActive())
{
CameraComponent->GetCameraView(DeltaTime, OutResult);
return;
}
}
}
GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
}
void UCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView)
{
if (IsXRHeadTrackedCamera())
{
HandleXRCamera();
}
if (bUsePawnControlRotation)
{
const APawn* OwningPawn = Cast<APawn>(GetOwner());
const AController* OwningController = OwningPawn ? OwningPawn->GetController() : nullptr;
if (OwningController && OwningController->IsLocalPlayerController())
{
const FRotator PawnViewRotation = OwningPawn->GetViewRotation();
if (!PawnViewRotation.Equals(GetComponentRotation()))
{
SetWorldRotation(PawnViewRotation);
}
}
}
if (bUseAdditiveOffset)
{
FTransform OffsetCamToBaseCam = AdditiveOffset;
FTransform BaseCamToWorld = GetComponentToWorld();
FTransform OffsetCamToWorld = OffsetCamToBaseCam * BaseCamToWorld;
DesiredView.Location = OffsetCamToWorld.GetLocation();
DesiredView.Rotation = OffsetCamToWorld.Rotator();
}
else
{
DesiredView.Location = GetComponentLocation();
DesiredView.Rotation = GetComponentRotation();
}
DesiredView.FOV = bUseAdditiveOffset ? (FieldOfView + AdditiveFOVOffset) : FieldOfView;
DesiredView.AspectRatio = AspectRatio;
DesiredView.bConstrainAspectRatio = bConstrainAspectRatio;
DesiredView.bUseFieldOfViewForLOD = bUseFieldOfViewForLOD;
DesiredView.ProjectionMode = ProjectionMode;
DesiredView.OrthoWidth = OrthoWidth;
DesiredView.OrthoNearClipPlane = OrthoNearClipPlane;
DesiredView.OrthoFarClipPlane = OrthoFarClipPlane;
if (bOverrideAspectRatioAxisConstraint)
{
DesiredView.AspectRatioAxisConstraint = AspectRatioAxisConstraint;
}
// See if the CameraActor wants to override the PostProcess settings used.
DesiredView.PostProcessBlendWeight = PostProcessBlendWeight;
if (PostProcessBlendWeight > 0.0f)
{
DesiredView.PostProcessSettings = PostProcessSettings;
}
// If this camera component has a motion vector simumlation transform, use that for the current view's previous transform
DesiredView.PreviousViewTransform = FMotionVectorSimulation::Get().GetPreviousTransform(this);
}
----------------------------------------------------------------------------------------------------------------------
当一个controller possessed一个character的时候,下面代码按顺序看
void APlayerController::OnPossess(APawn* PawnToPossess)
{
.................
ClientRestart(GetPawn());
.................
}
void APlayerController::ClientRestart_Implementation(APawn* NewPawn)
{
.....................
//继续看此函数
GetPawn()->PawnClientRestart();
if (GetLocalRole() < ROLE_Authority)
{
ChangeState( NAME_Playing );
if (bAutoManageActiveCameraTarget)
{
AutoManageActiveCameraTarget(GetPawn());
ResetCameraMode();
}
}
}
void APawn::PawnClientRestart()
{
Restart();
APlayerController* PC = Cast<APlayerController>(Controller);
if (PC && PC->IsLocalController())
{
// Handle camera possession
if (PC->bAutoManageActiveCameraTarget)
{
//看此函数,把这个pawn传进去
PC->AutoManageActiveCameraTarget(this);
}
// Set up player input component, if there isn't one already.
if (InputComponent == nullptr)
{
InputComponent = CreatePlayerInputComponent();
if (InputComponent)
{
SetupPlayerInputComponent(InputComponent);
InputComponent->RegisterComponent();
if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
{
InputComponent->bBlockInput = bBlockInput;
UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
}
}
}
}
}
void APlayerController::AutoManageActiveCameraTarget(AActor* SuggestedTarget)
{
if (bAutoManageActiveCameraTarget)
{
// See if there is a CameraActor with an auto-activate index that matches us.
if (GetNetMode() == NM_Client)
{
// Clients don't know their own index on the server, so they have to trust that if they use a camera with an auto-activate index, that's their own index.
ACameraActor* CurrentCameraActor = Cast<ACameraActor>(GetViewTarget());
if (CurrentCameraActor)
{
const int32 CameraAutoIndex = CurrentCameraActor->GetAutoActivatePlayerIndex();
if (CameraAutoIndex != INDEX_NONE)
{
return;
}
}
}
else
{
// See if there is a CameraActor in the level that auto-activates for this PC.
ACameraActor* AutoCameraTarget = GetAutoActivateCameraForPlayer();
if (AutoCameraTarget)
{
SetViewTarget(AutoCameraTarget);
return;
}
}
// No auto-activate CameraActor, so use the suggested target.
SetViewTarget(SuggestedTarget);
}
}
void APlayerController::SetViewTarget(class AActor* NewViewTarget, struct FViewTargetTransitionParams TransitionParams)
{
// if we're being controlled by a director track, update it with the new viewtarget
// so it returns to the proper viewtarget when it finishes.
UInterpTrackInstDirector* const Director = GetControllingDirector();
if (Director)
{
Director->OldViewTarget = NewViewTarget;
}
//
void APlayerController::SetViewTarget(class AActor* NewViewTarget, struct FViewTargetTransitionParams TransitionParams)
{
// if we're being controlled by a director track, update it with the new viewtarget
// so it returns to the proper viewtarget when it finishes.
UInterpTrackInstDirector* const Director = GetControllingDirector();
if (Director)
{
Director->OldViewTarget = NewViewTarget;
}
//把target传给了相机管理
if (PlayerCameraManager)
{
PlayerCameraManager->SetViewTarget(NewViewTarget, TransitionParams);
}
}
//在相机管理器中,这个函数每帧都调用 传的target就是 上面从pc里面设置的target
void APlayerCameraManager::UpdateViewTargetInternal(FTViewTarget& OutVT, float DeltaTime)
{
if (OutVT.Target)
{
FVector OutLocation;
FRotator OutRotation;
float OutFOV;
//如果蓝图定制了 loc rot fov
if (BlueprintUpdateCamera(OutVT.Target, OutLocation, OutRotation, OutFOV))
{
OutVT.POV.Location = OutLocation;
OutVT.POV.Rotation = OutRotation;
OutVT.POV.FOV = OutFOV;
}
else
{
OutVT.Target->CalcCamera(DeltaTime, OutVT.POV);
}
}
}
void AActor::CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult)
{
if (bFindCameraComponentWhenViewTarget)
{
// Look for the first active camera component and use that for the view
TInlineComponentArray<UCameraComponent*> Cameras;
GetComponents<UCameraComponent>(/*out*/ Cameras);
for (UCameraComponent* CameraComponent : Cameras)
{
if (CameraComponent->IsActive())
{
CameraComponent->GetCameraView(DeltaTime, OutResult);
return;
}
}
}
GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
}