1、cameracomponent的修改
void UCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView)
{
//xr的不管
if (GEngine && GEngine->XRSystem.IsValid() && GetWorld() && GetWorld()->WorldType != EWorldType::Editor )
{
IXRTrackingSystem* XRSystem = GEngine->XRSystem.Get();
auto XRCamera = XRSystem->GetXRCamera();
if (XRCamera.IsValid())
{
if (XRSystem->IsHeadTrackingAllowedForWorld(*GetWorld()))
{
const FTransform ParentWorld = CalcNewComponentToWorld(FTransform());
XRCamera->SetupLateUpdate(ParentWorld, this, bLockToHmd == 0);
if (bLockToHmd)
{
FQuat Orientation;
FVector Position;
if (XRCamera->UpdatePlayerCamera(Orientation, Position))
{
SetRelativeTransform(FTransform(Orientation, Position));
}
else
{
ResetRelativeTransform();
}
}
XRCamera->OverrideFOV(this->FieldOfView);
}
}
}
//是否用pawn的controllrotation 默认是true
if (bUsePawnControlRotation)
{
const APawn* OwningPawn = Cast<APawn>(GetOwner());
const AController* OwningController = OwningPawn ? OwningPawn->GetController() : nullptr;
if (OwningController && OwningController->IsLocalPlayerController())
{
//GetViewRotation()函数里面其实获得是controller的rotation
const FRotator PawnViewRotation = OwningPawn->GetViewRotation();
if (!PawnViewRotation.Equals(GetComponentRotation()))
{
SetWorldRotation(PawnViewRotation);
}
}
}
//还有offset功能默认是开启的
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;
// 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);
}
//并没有调用super
void ULyraCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView)
{
check(CameraModeStack);
//如果DetermineCameraModeDelegate有bind的cameramode就添加到CameraModeStack中
UpdateCameraModes();
FLyraCameraModeView CameraModeView;
//CameraModeStack开始更新
CameraModeStack->EvaluateStack(DeltaTime, CameraModeView);
//在父类中component的rotation被动的跟随controller的rotation
//但是在lyra中是多个cameramode共同blend后的ControlRotation再主动的影响pc的rotation
//这样做有啥好处呢?
// Keep player controller in sync with the latest view.
if (APawn* TargetPawn = Cast<APawn>(GetTargetActor()))
{
if (APlayerController* PC = TargetPawn->GetController<APlayerController>())
{
//把CameraModeView的ControlRotation强制更新pc的rotation
PC->SetControlRotation(CameraModeView.ControlRotation);
}
}
// Apply any offset that was added to the field of view.
CameraModeView.FieldOfView += FieldOfViewOffset;
FieldOfViewOffset = 0.0f;
// Keep camera component in sync with the latest view.
SetWorldLocationAndRotation(CameraModeView.Location, CameraModeView.Rotation);
FieldOfView = CameraModeView.FieldOfView;
// Fill in desired view.
DesiredView.Location = CameraModeView.Location;
DesiredView.Rotation = CameraModeView.Rotation;
DesiredView.FOV = CameraModeView.FieldOfView;
DesiredView.OrthoWidth = OrthoWidth;
DesiredView.OrthoNearClipPlane = OrthoNearClipPlane;
DesiredView.OrthoFarClipPlane = OrthoFarClipPlane;
DesiredView.AspectRatio = AspectRatio;
DesiredView.bConstrainAspectRatio = bConstrainAspectRatio;
DesiredView.bUseFieldOfViewForLOD = bUseFieldOfViewForLOD;
DesiredView.ProjectionMode = ProjectionMode;
// See if the CameraActor wants to override the PostProcess settings used.
DesiredView.PostProcessBlendWeight = PostProcessBlendWeight;
if (PostProcessBlendWeight > 0.0f)
{
DesiredView.PostProcessSettings = PostProcessSettings;
}
// 并没有cameracomponent的offset功能
}
流程方面:
每一帧都会调用ULyraCameraComponent::GetCameraView()
UpdateCameraModes()中
void ULyraCameraComponent::UpdateCameraModes()
{
check(CameraModeStack);
if (CameraModeStack->IsStackActivate())
{
//每一帧都会调用绑定在这个代理上的函数获得cameramode
if (DetermineCameraModeDelegate.IsBound())
{
if (const TSubclassOf<ULyraCameraMode> CameraMode = DetermineCameraModeDelegate.Execute())
{
CameraModeStack->PushCameraMode(CameraMode);
}
}
}
}
//在这个component中,当pawn完成初始化的时候
//把代理和函数hook一下
void ULyraHeroComponent::OnPawnReadyToInitialize()
{
if (!ensure(!bPawnHasInitialized))
{
// Don't initialize twice
return;
}
APawn* Pawn = GetPawn<APawn>();
if (!Pawn)
{
return;
}
const bool bIsLocallyControlled = Pawn->IsLocallyControlled();
ALyraPlayerState* LyraPS = GetPlayerState<ALyraPlayerState>();
check(LyraPS);
const ULyraPawnData* PawnData = nullptr;
if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn))
{
PawnData = PawnExtComp->GetPawnData<ULyraPawnData>();
// The player state holds the persistent data for this player (state that persists across deaths and multiple pawns).
// The ability system component and attribute sets live on the player state.
PawnExtComp->InitializeAbilitySystem(LyraPS->GetLyraAbilitySystemComponent(), LyraPS);
}
if (ALyraPlayerController* LyraPC = GetController<ALyraPlayerController>())
{
if (Pawn->InputComponent != nullptr)
{
InitializePlayerInput(Pawn->InputComponent);
}
}
if (bIsLocallyControlled && PawnData)
{
if (ULyraCameraComponent* CameraComponent = ULyraCameraComponent::FindCameraComponent(Pawn))
{
//在这里代理和函数bind一下,就是说每一帧都会调用DetermineCameraMode()函数
CameraComponent->DetermineCameraModeDelegate.BindUObject(this, &ThisClass::DetermineCameraMode);
}
}
bPawnHasInitialized = true;
}
TSubclassOf<ULyraCameraMode> ULyraHeroComponent::DetermineCameraMode() const
{
//有mode 就返回mode,这个mode是通过ga赋予的
if (AbilityCameraMode)
{
return AbilityCameraMode;
}
const APawn* Pawn = GetPawn<APawn>();
if (!Pawn)
{
return nullptr;
}
//如果没有技能的camera mode 就用pawndata中定义的角色默认的camera mode
if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn))
{
if (const ULyraPawnData* PawnData = PawnExtComp->GetPawnData<ULyraPawnData>())
{
return PawnData->DefaultCameraMode;
}
}
return nullptr;
}
void ULyraGameplayAbility::SetCameraMode(TSubclassOf<ULyraCameraMode> CameraMode)
{
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(SetCameraMode, );
if (ULyraHeroComponent* HeroComponent = GetHeroComponentFromActorInfo())
{
HeroComponent->SetAbilityCameraMode(CameraMode, CurrentSpecHandle);
ActiveCameraMode = CameraMode;
}
}
void ULyraHeroComponent::SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle)
{
if (CameraMode)
{
AbilityCameraMode = CameraMode;
AbilityCameraModeOwningSpecHandle = OwningSpecHandle;
}
}
技能用完就把技能cameramode撤销
//这个是个蓝图函数在技能的end中调用
void ULyraGameplayAbility::ClearCameraMode()
{
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(ClearCameraMode, );
if (ActiveCameraMode)
{
if (ULyraHeroComponent* HeroComponent = GetHeroComponentFromActorInfo())
{
HeroComponent->ClearAbilityCameraMode(CurrentSpecHandle);
}
ActiveCameraMode = nullptr;
}
}
简单来说就是有个默认的cameramode ,一旦有ga要求自己的camera mode 就会把ga 的mode添加到cameramodestack中
下面就是多个camera mode切换的时候是如何blend的
//此函数每帧都会执行
void ULyraCameraModeStack::PushCameraMode(TSubclassOf<ULyraCameraMode> CameraModeClass)
{
if (!CameraModeClass)
{
return;
}
//如果在instance的数组中找到已经有初始化的对象就直接返回。
ULyraCameraMode* CameraMode = GetCameraModeInstance(CameraModeClass);
check(CameraMode);
int32 StackSize = CameraModeStack.Num();
//如果要添加的cameramode 已经是在第一个了,就直接return
if ((StackSize > 0) && (CameraModeStack[0] == CameraMode))
{
// Already top of stack.
return;
}
//如果第一个不等于要添加的,就for一下,如果在其他位置找到了,先remove再添加到第一个位置
//假如数组中没有新来的,那么新来的weight最后值是0
//如果新来的在数组里有,但是不是第一个,那么新来的weight会继承之前的weight
// See if it's already in the stack and remove it.
// Figure out how much it was contributing to the stack.
int32 ExistingStackIndex = INDEX_NONE;
float ExistingStackContribution = 1.0f;
for (int32 StackIndex = 0; StackIndex < StackSize; ++StackIndex)
{
if (CameraModeStack[StackIndex] == CameraMode)
{
ExistingStackIndex = StackIndex;
ExistingStackContribution *= CameraMode->GetBlendWeight();
break;
}
else
{
ExistingStackContribution *= (1.0f - CameraModeStack[StackIndex]->GetBlendWeight());
}
}
if (ExistingStackIndex != INDEX_NONE)
{
CameraModeStack.RemoveAt(ExistingStackIndex);
StackSize--;
}
else
{
ExistingStackContribution = 0.0f;
}
// Decide what initial weight to start with.
const bool bShouldBlend = ((CameraMode->GetBlendTime() > 0.0f) && (StackSize > 0));
const float BlendWeight = (bShouldBlend ? ExistingStackContribution : 1.0f);
CameraMode->SetBlendWeight(BlendWeight);
// Add new entry to top of stack.
CameraModeStack.Insert(CameraMode, 0);
// Make sure stack bottom is always weighted 100%.
CameraModeStack.Last()->SetBlendWeight(1.0f);
// Let the camera mode know if it's being added to the stack.
if (ExistingStackIndex == INDEX_NONE)
{
CameraMode->OnActivation();
}
}