unreal 获取相机_unreal 360度相机 - CSDN
  • UE4中的相机操控方案

    千次阅读 2018-10-09 22:13:20
    在UE4中的相机操控方案可能会比U3D中的方式要稍微麻烦一点点,今天分享下UE4中相机的几种操控方式 在本文之前先创建一个继承自GameModeBase和一个继承自APawn类,在这里博主分别命名为CameraGameModeBase、...

    在UE4中的相机操控方案可能会比U3D中的方式要稍微麻烦一点点,今天分享下UE4中相机的几种操控方式

    在本文之前先创建一个继承自GameModeBase和一个继承自APawn类,在这里博主分别命名为CameraGameModeBase、CameraCharacter

    在CameraGameModeBase构造函数里将CameraCharacter设置为默认Apawn,代码如下:

    DefaultPawnClass = ACameraCharacter::StaticClass();

    在CameraCharacter中重写SetupPlayerInputComponent函数,用于绑定本文需要绑定的操控输入事件

    // 调用绑定输入事件
    void ACameraCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    	//向上滚轮
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("ScrollWheelUp", EKeys::MouseWheelAxis, 10));
    	PlayerInputComponent->BindAxis("ScrollWheelUp", this, &ACameraCharacter::OnScrollWheelUpPress);
    
    	//鼠标右键
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("MouseRightDrag", EKeys::RightMouseButton, 10));
    	PlayerInputComponent->BindAxis("MouseRightDrag", this, &ACameraCharacter::OnMouseRightDrag);
    
    	//键盘Shift键
    	UPlayerInput::AddEngineDefinedActionMapping(FInputActionKeyMapping("KeyLeftShift", EKeys::LeftShift));
    	PlayerInputComponent->BindAction("KeyLeftShift", IE_Pressed, this, &ACameraCharacter::OnKeyLeftShiftPress);
    	PlayerInputComponent->BindAction("KeyLeftShift", IE_Released, this, &ACameraCharacter::OnKeyLeftShiftReleased);
    
    	//鼠标位置(X,Y方向)
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("Turn", EKeys::MouseX, 1.0f));
    	PlayerInputComponent->BindAxis("Turn", this, &ACameraCharacter::OnTurn);
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("LookAtRotate", EKeys::MouseY, 1.0f));
    	PlayerInputComponent->BindAxis("LookAtRotate", this, &ACameraCharacter::OnLookAtRotate);
    }

    有了前面的基础,博主要带领大家实现相机的三种操控方案

    1.滚动鼠标滑轮,移动相机到鼠标点位置

    需要跟随鼠标点移动的话,需要通过当前鼠标点的位置获取到一个世界坐标位置,UE4提供了这个方法,代码如下:

    UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(GWorld, 0), CursorPos, WorldPos, MoveDirction);

    第一个参数是指指定的的控制器

    第二个参数是指当前鼠标位置

    第三第四个参数是指引用返回世界位置点与鼠标点指向的世界方向射线(就是我们需要获取到的移动方向)

    有了这个移动方向后,我们只需要在世界空间下,移动摄像机在世界空间下的方位就好了,这一功能代码如下:

    //滚动滑轮
    void ACameraCharacter::OnScrollWheelUpPress(float axisValue)
    {
    	FVector2D CursorPos;
    	FVector WorldPos;
    	FVector MoveDirction = FVector::ZeroVector;
    
    	if (FMath::Abs(axisValue) > KINDA_SMALL_NUMBER)
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(CursorPos.X, CursorPos.Y);
    		UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(GWorld, 0), CursorPos, WorldPos, MoveDirction);
    	}
    
    	ViewCamera->AddWorldOffset(MoveDirction*ScrollWheelSpeed*axisValue);
    }

    2.按住Shift键,拖拽鼠标右键平移视野

    通过当前帧鼠标在屏幕下的位置减去前一帧的鼠标位置得到一个位置向量

    通过这个比例改变摄像机自身坐标系中的X,Y轴坐标 ,代码如下:

    //计算在屏幕中的MoveOffset(前一个鼠标点到当前鼠标点的向量)
    void ACameraCharacter::CalcCameraMoveDrogDirction()
    {
    	if (FMath::Abs(FVector2D::Distance(FontCurorPos, CurrentCurcorPos)) < KINDA_SMALL_NUMBER)
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(FontCurorPos.X, FontCurorPos.Y);
    	}
    	else
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(CurrentCurcorPos.X, CurrentCurcorPos.Y);
    		FVector2D MoveOffset = CurrentCurcorPos - FontCurorPos;
    
    		FontCurorPos = CurrentCurcorPos;
    
    		ViewCamera->AddLocalOffset(FVector(0, -MoveOffset.X, MoveOffset.Y));
    	}
    }

    3.按住鼠标右键,移动鼠标绕点旋转

    实现这个操作可以让我们的CameraCharacter绑定一个弹簧手臂,然后再弹簧手臂上添加我们的摄像机

    这样我们可以通过改变控制器的旋转进而带动摄像机手臂以及摄像机达到旋转的目的

    绑定弹簧手臂方法如下

    // Sets default values
    ACameraCharacter::ACameraCharacter()
    {
    	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
    
    	/*创建弹簧手臂和摄像机*/
     	CameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraSpringArm"));
     	CameraSpringArm->SetupAttachment(RootComponent);
     	CameraSpringArm->TargetArmLength = 500.f;
     	CameraSpringArm->TargetOffset = FVector(100.f, 100.f, 100.f);
     	CameraSpringArm->bUsePawnControlRotation = true;
    	CameraSpringArm->SetWorldLocation(FVector::ZeroVector);
    	
    	//初始化摄像机
    	ViewCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("ViewCamera"));
    	ViewCamera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName);
    	ViewCamera->bUsePawnControlRotation = false;
    	ViewCamera->SetActive(true);
    }

    然后我们移动鼠标右键代码如下:

    void ACameraCharacter::OnTurn(float axisValue)
    {
    	if (!IsRotateCameraState) return;
    	if (IsRotateCameraState&&FMath::Abs(axisValue) > KINDA_SMALL_NUMBER)
    	{
    		AddControllerYawInput(-axisValue);
    	}
    }
    
    void ACameraCharacter::OnLookAtRotate(float axisValue)
    {
    	if (!IsRotateCameraState) return;
    	if (IsRotateCameraState && FMath::Abs(axisValue) > KINDA_SMALL_NUMBER)
    	{
    		AddControllerPitchInput(-axisValue);
    	}
    }

    最后给大家贴出这个案例的完整代码:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "SCTCameraCharacter.h"
    #include "Camera/CameraComponent.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "GameFramework/PlayerInput.h"
    #include "Kismet/GameplayStatics.h"
    #include "UnrealMathUtility.h"
    #include "Engine/Engine.h"
    #include "GameFramework/Controller.h"
    #include "GameFramework/Character.h"
    #include "Components/CapsuleComponent.h"
    
    // Sets default values
    ACameraCharacter::ACameraCharacter()
    {
    	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
    
    	/*创建弹簧手臂和摄像机*/
     	CameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraSpringArm"));
     	CameraSpringArm->SetupAttachment(RootComponent);
     	CameraSpringArm->TargetArmLength = 500.f;
     	CameraSpringArm->TargetOffset = FVector(100.f, 100.f, 100.f);
     	CameraSpringArm->bUsePawnControlRotation = true;
    	CameraSpringArm->SetWorldLocation(FVector::ZeroVector);
    	
    	//初始化摄像机
    	ViewCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("ViewCamera"));
    	ViewCamera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName);
    	ViewCamera->bUsePawnControlRotation = false;
    	ViewCamera->SetActive(true);
    }
    
    // Called when the game starts or when spawned
    void ACameraCharacter::BeginPlay()
    {
    	Super::BeginPlay();
    
    	//初始化变量
    	ScrollWheelSpeed = 2;
    
    	CurrentCurcorPos = FontCurorPos = FVector2D::ZeroVector;
    
    	IsBindShiftKey = false;
    
    	IsRotateCameraState = false;
    	IsMoveCameraState = false;
    
    	FInputModeGameAndUI InputMode;
    	InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
    	InputMode.SetHideCursorDuringCapture(false);
    	UGameplayStatics::GetPlayerController(GWorld, 0)->SetInputMode(InputMode);
    
    	UGameplayStatics::GetPlayerController(GWorld, 0)->bShowMouseCursor = 1;
    }
    
    void ACameraCharacter::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	if (IsMoveCameraState)
    	{
    		CalcCameraMoveDrogDirction();
    	}
    }
    
    // 调用绑定输入事件
    void ACameraCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    	//向上滚轮
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("ScrollWheelUp", EKeys::MouseWheelAxis, 10));
    	PlayerInputComponent->BindAxis("ScrollWheelUp", this, &ACameraCharacter::OnScrollWheelUpPress);
    
    	//鼠标右键
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("MouseRightDrag", EKeys::RightMouseButton, 10));
    	PlayerInputComponent->BindAxis("MouseRightDrag", this, &ACameraCharacter::OnMouseRightDrag);
    
    	//键盘Shift键
    	UPlayerInput::AddEngineDefinedActionMapping(FInputActionKeyMapping("KeyLeftShift", EKeys::LeftShift));
    	PlayerInputComponent->BindAction("KeyLeftShift", IE_Pressed, this, &ACameraCharacter::OnKeyLeftShiftPress);
    	PlayerInputComponent->BindAction("KeyLeftShift", IE_Released, this, &ACameraCharacter::OnKeyLeftShiftReleased);
    
    	//鼠标位置(X,Y方向)
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("Turn", EKeys::MouseX, 1.0f));
    	PlayerInputComponent->BindAxis("Turn", this, &ACameraCharacter::OnTurn);
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("LookAtRotate", EKeys::MouseY, 1.0f));
    	PlayerInputComponent->BindAxis("LookAtRotate", this, &ACameraCharacter::OnLookAtRotate);
    }
    
    //滚动滑轮
    void ACameraCharacter::OnScrollWheelUpPress(float axisValue)
    {
    	FVector2D CursorPos;
    	FVector WorldPos;
    	FVector MoveDirction = FVector::ZeroVector;
    
    	if (FMath::Abs(axisValue) > KINDA_SMALL_NUMBER)
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(CursorPos.X, CursorPos.Y);
    		UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(GWorld, 0), CursorPos, WorldPos, MoveDirction);
    	}
    
    	ViewCamera->AddWorldOffset(MoveDirction*ScrollWheelSpeed*axisValue);
    }
    
    //鼠标右键拖拽
    void ACameraCharacter::OnMouseRightDrag(float axisValue)
    {
    	if (FMath::Abs(axisValue) < KINDA_SMALL_NUMBER)
    	{
    		CurrentCurcorPos = FontCurorPos = FVector2D::ZeroVector;
    		IsRotateCameraState = false;
    		IsMoveCameraState = false;
    	}
    	else
    	{
    		//按下左shift键,开始拖拽
    		if (IsBindShiftKey)
    		{
    			//拖拽状态
    			IsMoveCameraState = true;
    		}
    		//没有按下左Shift键时候绕鼠标点旋转
    		else
    		{
    			IsRotateCameraState = true;
    		}
    	}
    }
    
    //计算在屏幕中的MoveOffset(前一个鼠标点到当前鼠标点的向量)
    void ACameraCharacter::CalcCameraMoveDrogDirction()
    {
    	if (FMath::Abs(FVector2D::Distance(FontCurorPos, CurrentCurcorPos)) < KINDA_SMALL_NUMBER)
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(FontCurorPos.X, FontCurorPos.Y);
    	}
    	else
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(CurrentCurcorPos.X, CurrentCurcorPos.Y);
    		FVector2D MoveOffset = CurrentCurcorPos - FontCurorPos;
    
    		FontCurorPos = CurrentCurcorPos;
    
    		ViewCamera->AddLocalOffset(FVector(0, -MoveOffset.X, MoveOffset.Y));
    	}
    }
    
    void ACameraCharacter::OnKeyLeftShiftPress()
    {
    	IsBindShiftKey = true;
    }
    
    void ACameraCharacter::OnKeyLeftShiftReleased()
    {
    	IsBindShiftKey = false;
    }
    
    void ACameraCharacter::OnTurn(float axisValue)
    {
    	if (!IsRotateCameraState) return;
    	if (IsRotateCameraState&&FMath::Abs(axisValue) > KINDA_SMALL_NUMBER)
    	{
    		AddControllerYawInput(-axisValue);
    	}
    }
    
    void ACameraCharacter::OnLookAtRotate(float axisValue)
    {
    	if (!IsRotateCameraState) return;
    	if (IsRotateCameraState && FMath::Abs(axisValue) > KINDA_SMALL_NUMBER)
    	{
    		AddControllerPitchInput(-axisValue);
    	}
    }
    
    
    

    除了以上这种方法还有一种方法,UE4在AActor类中提供给了一个虚方法,继承自AActor的类通过重写ClacCamera虚函数的OutResult引用变量可以改变摄像机位置和旋转,实现代码博主直接贴出来,有兴趣的朋友可以看看:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "CameraCharacter.h"
    #include "Camera/CameraComponent.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "GameFramework/PlayerInput.h"
    #include "Kismet/GameplayStatics.h"
    #include "UnrealMathUtility.h"
    #include "Engine/Engine.h"
    #include "GameFramework/Controller.h"
    #include "GameFramework/Character.h"
    #include "Components/CapsuleComponent.h"
    
    // Sets default values
    ACameraCharacter::ACameraCharacter()
    {
    	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	GetCapsuleComponent()->SetEnableGravity(false);
    
    	/*创建弹簧手臂和摄像机*/
    	//摄像机手臂
    	CameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraSpringArm"));
    	CameraSpringArm->SetupAttachment(RootComponent);
    	//设置距离
    	CameraSpringArm->TargetArmLength = 300.f;
    	//设置偏移
    	CameraSpringArm->TargetOffset = FVector(0.f, 0.f, 0.f);
    	//绑定Controller的旋转
    	CameraSpringArm->bUsePawnControlRotation = true;
    	//初始化第三人称摄像机
    	ViewCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("ViewCamera"));
    	//将相机绑定到摄像机手臂
    	ViewCamera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName);
    	//设置ThirdCamera不跟随控制器的旋转
    	ViewCamera->bUsePawnControlRotation = false;
    	//处于激活状态
    	ViewCamera->SetActive(true);
    }
    
    // Called when the game starts or when spawned
    void ACameraCharacter::BeginPlay()
    {
    	Super::BeginPlay();
    
    	//初始化变量
    	MoveDirction = FVector::ZeroVector;
    	CameraLocation = ViewCamera->GetSocketLocation(USpringArmComponent::SocketName);
    	ScrollWheelSpeed = 50;
    
    	CurrentCurcorPos = FontCurorPos = FVector2D::ZeroVector;
    
    	IsBindShiftKey = false;
    
    	IsRotateCameraState = false;
    
    	RoundCameraDistTarget = 1000.f;
    	RoundCameraTargetOffset = FVector::ZeroVector;
    	RoundCameraDistCur = 1000.f;
    
    	CameraOriginLocation = FVector::ZeroVector;
    	CameraOriginRotate = FRotator::ZeroRotator;
    }
    
    void ACameraCharacter::CalcCamera(float DeltaTime, struct FMinimalViewInfo& OutResult)
    {
    	if (ViewCamera->IsVisible())
    	{
    		if (bFindCameraComponentWhenViewTarget)
    		{
    			ViewCamera->GetCameraView(DeltaTime, OutResult);
    		}
    	}
    	else
    	{
    		GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
    	}
    
    	if (CameraOriginLocation != FVector::ZeroVector&&CameraOriginRotate != FRotator::ZeroRotator)
    	{
    		OutResult.Location = CameraOriginLocation;
    		OutResult.Rotation = CameraOriginRotate;
    	}
    
    	if (IsRotateCameraState)
    	{
    		OutResult.Rotation.Yaw = GetControlRotation().Yaw;
    		OutResult.Rotation.Pitch = GetControlRotation().Pitch;
    		OutResult.Rotation.Roll = 0;
    		OutResult.Location = RoundCameraTargetOffset;
    		OutResult.Location -= OutResult.Rotation.Vector() * RoundCameraDistCur;
    		RoundCameraDistCur = FMath::FInterpTo(RoundCameraDistCur, RoundCameraDistTarget, DeltaTime, 20.f);
    
    		CameraLocation = OutResult.Location;
    	}
    	else
    	{
    		//滚动位置变化
    		CameraLocation += MoveDirction*ScrollWheelSpeed;
    		//平移位置变化
    		CameraLocation += FVector(0, MoveOffset.X, -MoveOffset.Y);
    		if (CameraLocation != FVector::ZeroVector)
    		{
    			OutResult.Location = CameraLocation;
    		}
    	}
    
    	CameraOriginLocation = OutResult.Location;
    	CameraOriginRotate = OutResult.Rotation;
    }
    
    void ACameraCharacter::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	if (OnStartMoveCamera.IsBound())
    	{
    		OnStartMoveCamera.ExecuteIfBound();
    	}
    
    	if (OnStartRotateAroundCamera.IsBound())
    	{
    		OnStartRotateAroundCamera.ExecuteIfBound();
    	}
    }
    
    // 调用绑定输入事件
    void ACameraCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    	//向上滚轮
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("ScrollWheelUp", EKeys::MouseWheelAxis, 10));
    	PlayerInputComponent->BindAxis("ScrollWheelUp", this, &ACameraCharacter::OnScrollWheelUpPress);
    
    	//鼠标右键
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("MouseRightDrag", EKeys::RightMouseButton, 10));
    	PlayerInputComponent->BindAxis("MouseRightDrag", this, &ACameraCharacter::OnMouseRightDrag);
    
    	//键盘Shift键
    	UPlayerInput::AddEngineDefinedActionMapping(FInputActionKeyMapping("KeyLeftShift", EKeys::LeftShift));
    	PlayerInputComponent->BindAction("KeyLeftShift", IE_Pressed, this, &ACameraCharacter::OnKeyLeftShiftPress);
    	PlayerInputComponent->BindAction("KeyLeftShift", IE_Released, this, &ACameraCharacter::OnKeyLeftShiftReleased);
    
    	//鼠标位置(X,Y方向)
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("Turn", EKeys::MouseX, 10));
    	PlayerInputComponent->BindAxis("Turn", this, &ACameraCharacter::OnTurn);
    	UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("LookAtRotate", EKeys::MouseY, 10));
    	PlayerInputComponent->BindAxis("LookAtRotate", this, &ACameraCharacter::OnLookAtRotate);
    }
    
    //滚动滑轮
    void ACameraCharacter::OnScrollWheelUpPress(float axisValue)
    {
    	FVector2D CursorPos;
    	FVector WorldPos;
    	MoveDirction = FVector::ZeroVector;
    
    	if (axisValue != 0)
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(CursorPos.X, CursorPos.Y);
    		UGameplayStatics::DeprojectScreenToWorld(GetWorld()->GetFirstPlayerController(), CursorPos, WorldPos, MoveDirction);
    
    		if (axisValue < 0)
    		{
    			MoveDirction = -MoveDirction;
    		}
    
    		GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::White, MoveDirction.ToString());
    	}
    }
    
    //鼠标右键拖拽
    void ACameraCharacter::OnMouseRightDrag(float axisValue)
    {
    	if (axisValue == 0)
    	{
    		CurrentCurcorPos = FontCurorPos = FVector2D::ZeroVector;
    		MoveOffset = FVector2D::ZeroVector;
    		IsRotateCameraState = false;
    
    		OnStartMoveCamera.Unbind();
    	}
    	else
    	{
    		//按下左shift键,开始拖拽
    		if (IsBindShiftKey)
    		{
    			//拖拽状态
    			OnStartMoveCamera.BindUObject(this, &ACameraCharacter::CalcCameraMoveDrogDirction);
    		}
    		//没有按下左Shift键时候绕鼠标点旋转
    		else
    		{
    			IsRotateCameraState = true;
    		}
    	}
    }
    
    //计算在屏幕中的MoveOffset(前一个鼠标点到当前鼠标点的向量)
    void ACameraCharacter::CalcCameraMoveDrogDirction()
    {
    	if (FVector2D::Distance(FontCurorPos, CurrentCurcorPos) == 0)
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(FontCurorPos.X, FontCurorPos.Y);
    	}
    	else
    	{
    		GetWorld()->GetFirstPlayerController()->GetMousePosition(CurrentCurcorPos.X, CurrentCurcorPos.Y);
    		MoveOffset = CurrentCurcorPos - FontCurorPos;
    
    		FontCurorPos = CurrentCurcorPos;
    	}
    }
    
    
    void ACameraCharacter::OnKeyLeftShiftPress()
    {
    	IsBindShiftKey = true;
    }
    
    void ACameraCharacter::OnKeyLeftShiftReleased()
    {
    	IsBindShiftKey = false;
    }
    
    void ACameraCharacter::OnTurn(float axisValue)
    {
    	if (!IsRotateCameraState) return;
    	//if (axisValue>0)
    	{
    		AddControllerYawInput(axisValue);
    		RoundCameraTargetOffset += FRotator(0, 90, 0).Vector() * axisValue * 160.f * GetWorld()->GetDeltaSeconds() * RoundCameraDistTarget / 500.f;
    	}
    }
    
    
    void ACameraCharacter::OnLookAtRotate(float axisValue)
    {
    	if (!IsRotateCameraState) return;
    	//if (axisValue > 0)
    	{
    		AddControllerPitchInput(axisValue);
    		RoundCameraTargetOffset += FRotator(0, 0, 0).Vector() * axisValue * 160.f * GetWorld()->GetDeltaSeconds() * RoundCameraDistTarget / 500.f;
    	}
    }
    
    
    

    备注:在创建一个继承自ACharacter的类会自带一个默认的摄像机,当在其添加了一个摄像机组件后替换这个摄像机

    结语:博主今后会持续更新UE4、U3D的学习内容,大家多多支持!

    博客地址:blog.liujunliang.com.cn

    展开全文
  • 第一步:在“模式”下的搜索栏搜索“camera”,找到相机并拖拽至游戏界面中。 第二步:为自己的游戏模式创建一个蓝图子类。右键原有“GameMode”,选择“创建基于XXXX的蓝图类”。(这一步与本篇无关) 第三步:在...

    设置摄像机视角为玩家视角

    第一步:在“模式”下的搜索栏搜索“camera”,找到相机并拖拽至游戏界面中。
    在“模式”下的搜索栏搜索“camera”,找到相机并拖拽至游戏界面中。
    第二步:为自己的游戏模式创建一个蓝图子类。右键原有“GameMode”,选择“创建基于XXXX的蓝图类”。(这一步与本篇无关)
    在这里插入图片描述
    第三步:在创建好GameMode的蓝图类后,将该类设置成游戏模式。
    在这里插入图片描述
    第四步:先点击被拖拽进游戏界面中的摄像机,再依次点击上方“蓝图”——“打开关卡蓝图”。
    在这里插入图片描述
    第五步:右键空白处,点击“创建一个对CameraActor的引用”;之后同样步骤,在搜索栏搜索“controller”,点击“获取玩家控制器”;之后先把右上角“情景关联”的勾点没,然后继续在搜索栏搜索“view target”,打开“使用混合设置用户目标”。之后按下图连接。
    在这里插入图片描述
    第六步:点击左上角“编译”、“保存”。回到主界面,点击游戏界面里的相机,右下角出现相机的视角内容。调整相机高度和位置,再点击“播放”即可。
    在这里插入图片描述

    本篇学习来自“Siki学院吃豆人教程 P24”。

    展开全文
  • 下面这个设置好像只有一个有作用,无法同时控制两个物体。 //Take control of the ...这个程序是让物体附加一个相机,应该移动和视图都是针对物体的,和之前的Game-Controlled Cameras还是有区别的,Game-Controll

    下面这个设置好像只有一个有作用,无法同时控制两个物体。

        //Take control of the default Player
        AutoPossessPlayer = EAutoReceiveInput::Player0;

    这个程序是让物体附加一个相机,应该移动和视图都是针对物体的,和之前的Game-Controlled Cameras还是有区别的,Game-Controlled Camera没有依附特定的物体,直接写在程序的两个变量上进行控制,而这个例子使用的是UCameraComponent,attach到根节点。

    放上代码,和之前的例子没有什么区别,那么这个C++ Programming Tutorials中的七个例子还剩下两个例子,First Person Shooter Tutorial和User Interface With UMG.这两个例子暂时先不写,已经能写基本的程序,需要弄清楚它们的类是干什么的。很明显的tutorial上有个错误是编译不过的,但是自己参考API修改过来了。

    Performing 3 actions (4 in parallel)
    @progress 'Compiling C++ source code...' 0%
    [2/3] Compile PawnWithCamera.cpp
    [1/3] Compile PawnWithCamera.gen.cpp
    /home/wang/Documents/Unreal Projects/UnrealLearn/Source/UnrealLearn/PawnWithCamera.cpp:75:43: error: 
          no member named 'SafeNormal' in 'FVector2D'
                MovementInput = MovementInput.SafeNormal() * 100.0f;
                                ~~~~~~~~~~~~~ ^
    1 error generated.
    @progress 'Compiling C++ source code...' 25%
    @progress 'Compiling C++ source code...' 50%
    @progress 'Compiling C++ source code...' 75%
    

    可以看到编译的时候SafeNormal编译提示上说FVector2D没有这个方法,所以查看Document发现应该使用GetSafeNormal(),所以会查阅还是很重要的,之前就有很多的头文件都是通过查找获取来的,这点官网还做得比较好,附上代码。

    PawnWithCamera.h

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Pawn.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    #include "PawnWithCamera.generated.h"
    
    UCLASS()
    class UNREALLEARN_API APawnWithCamera : public APawn
    {
    	GENERATED_BODY()
    
    public:
    	// Sets default values for this pawn's properties
    	APawnWithCamera();
    
    protected:
    	// Called when the game starts or when spawned
    	virtual void BeginPlay() override;
    
    public:	
    	// Called every frame
    	virtual void Tick(float DeltaTime) override;
    
    	// Called to bind functionality to input
    	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
    
    protected:
        UPROPERTY(EditAnywhere)
        USpringArmComponent* OurCameraSpringArm;
        UCameraComponent* OurCamera;
    	
    	//Input variables
        FVector2D MovementInput;
        FVector2D CameraInput;
        float ZoomFactor;
        bool bZoomingIn;
    
        //Input functions
        void MoveForward(float AxisValue);
        void MoveRight(float AxisValue);
        void PitchCamera(float AxisValue);
        void YawCamera(float AxisValue);
        void ZoomIn();
        void ZoomOut();
    };
    
    PawnWithCamera.cpp

    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "PawnWithCamera.h"
    
    // Sets default values
    APawnWithCamera::APawnWithCamera()
    {
     	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    	PrimaryActorTick.bCanEverTick = true;
    
    	//Create our components
        RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
        OurCameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraSpringArm"));
        OurCameraSpringArm->SetupAttachment(RootComponent);
        OurCameraSpringArm->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, 50.0f), FRotator(-60.0f, 0.0f, 0.0f));
        OurCameraSpringArm->TargetArmLength = 400.f;
        OurCameraSpringArm->bEnableCameraLag = true;
        OurCameraSpringArm->CameraLagSpeed = 3.0f;
        OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("GameCamera"));
        OurCamera->SetupAttachment(OurCameraSpringArm, USpringArmComponent::SocketName);
    
        //Take control of the default Player
        AutoPossessPlayer = EAutoReceiveInput::Player0;
    
    }
    
    // Called when the game starts or when spawned
    void APawnWithCamera::BeginPlay()
    {
    	Super::BeginPlay();
    	
    }
    
    // Called every frame
    void APawnWithCamera::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    	
    	//Zoom in if ZoomIn button is down, zoom back out if it's not
        {
            if (bZoomingIn)
            {
                ZoomFactor += DeltaTime / 0.5f;         //Zoom in over half a second
            }
            else
            {
                ZoomFactor -= DeltaTime / 0.25f;        //Zoom out over a quarter of a second
            }
            ZoomFactor = FMath::Clamp<float>(ZoomFactor, 0.0f, 1.0f);
            //Blend our camera's FOV and our SpringArm's length based on ZoomFactor
            OurCamera->FieldOfView = FMath::Lerp<float>(90.0f, 60.0f, ZoomFactor);
            OurCameraSpringArm->TargetArmLength = FMath::Lerp<float>(400.0f, 300.0f, ZoomFactor);
        }
    
        //Rotate our actor's yaw, which will turn our camera because we're attached to it
        {
            FRotator NewRotation = GetActorRotation();
            NewRotation.Yaw += CameraInput.X;
            SetActorRotation(NewRotation);
        }
    
        //Rotate our camera's pitch, but limit it so we're always looking downward
        {
            FRotator NewRotation = OurCameraSpringArm->GetComponentRotation();
            NewRotation.Pitch = FMath::Clamp(NewRotation.Pitch + CameraInput.Y, -80.0f, -15.0f);
            OurCameraSpringArm->SetWorldRotation(NewRotation);
        }
    
        //Handle movement based on our "MoveX" and "MoveY" axes
        {
            if (!MovementInput.IsZero())
            {
                //Scale our movement input axis values by 100 units per second
                MovementInput = MovementInput.GetSafeNormal() * 100.0f;
                FVector NewLocation = GetActorLocation();
                NewLocation += GetActorForwardVector() * MovementInput.X * DeltaTime;
                NewLocation += GetActorRightVector() * MovementInput.Y * DeltaTime;
                SetActorLocation(NewLocation);
            }
        }
    
    }
    
    // Called to bind functionality to input
    void APawnWithCamera::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	//Hook up events for "ZoomIn"
        InputComponent->BindAction("ZoomIn", IE_Pressed, this, &APawnWithCamera::ZoomIn);
        InputComponent->BindAction("ZoomIn", IE_Released, this, &APawnWithCamera::ZoomOut);
    
        //Hook up every-frame handling for our four axes
        InputComponent->BindAxis("MoveForward", this, &APawnWithCamera::MoveForward);
        InputComponent->BindAxis("MoveRight", this, &APawnWithCamera::MoveRight);
        InputComponent->BindAxis("CameraPitch", this, &APawnWithCamera::PitchCamera);
        InputComponent->BindAxis("CameraYaw", this, &APawnWithCamera::YawCamera);
    }
    
    //Input functions
    void APawnWithCamera::MoveForward(float AxisValue)
    {
        MovementInput.X = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
    }
    
    void APawnWithCamera::MoveRight(float AxisValue)
    {
        MovementInput.Y = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
    }
    
    void APawnWithCamera::PitchCamera(float AxisValue)
    {
        CameraInput.Y = AxisValue;
    }
    
    void APawnWithCamera::YawCamera(float AxisValue)
    {
        CameraInput.X = AxisValue;
    }
    
    void APawnWithCamera::ZoomIn()
    {
        bZoomingIn = true;
    }
    
    void APawnWithCamera::ZoomOut()
    {
        bZoomingIn = false;
    }


    展开全文
  • UE4摄像机系统解析

    万次阅读 多人点赞 2018-03-03 11:57:01
    一.摄像机工作原理在游戏中,摄像机是玩家的眼睛,他控制了玩家的视点(POV即PointOfView,后面简称POV)位置以及玩家的视野大小(FOV即FieldOfView,后面简称FOV)。一句话,摄像机决定了我们去观察这个游戏世界。...


    一.摄像机工作原理

    在游戏中,摄像机是玩家的眼睛,他控制了玩家的视点(POV即PointOfView,后面简称POV)位置以及玩家的视野大小(FOV即FieldOfView,后面简称FOV)。一句话,摄像机决定了我们去观察这个游戏世界。

    游戏的类型多种多样,有第一人称的FPS游戏,有第三人称的动作游戏,还有需要统筹全局来观察的RTS游戏。简单来说,第一人称就是把POV放在人眼睛的位置,第三人称就是把POV放在人身后一定距离的位置,RTS就是把POV放到离地面很高的位置。这里说POV要比说摄像机更为准确,因为有的时候摄像机只是一个为了方便大家理解与观察的实体,其实他的位置可以随意,不过为了便于大家理解与使用,我们一般将摄像机位置与视点位置同步。下图的摄像机位置即为POV的位置,紫色的框即为FOV。


    图1-1值为90的FOV

    图1-2值为40的FOV

    因为POV在游戏中是会随时变化的,所以我们需要在Tick里面去更新他的位置。所以,从本质上讲,调整摄像机就是不断地更新POV的位置,这样我们也能平滑流畅的观察游戏世界。如果,我们想要切换不同的视角,那就切换我们的POV。如果想要做一些镜头移动特效,就可以利用一些插值的算法来处理POV的位置。如果想要做一些视觉特效,可以直接在摄像机上加一些后处理效果。总之,还是那句话,摄像机决定你如何观察游戏世界。

    二.UE4摄像机关系梳理


    首先放一张摄像机相关类的关系图,


     图2-1摄像机相关类图

    下面开始一一分析各个类之间的关系。

    由于大家一般会先去看官方文档,这里就按照官方文档的顺序来解释。

    2.1 CameraComponent和CameraActor

    CameraComponent组件一般放在控制角色的根节点上,常规的行为与属性都可以在其中进行设置包括POV位置(即组件的位置),FOV,观察模式(分为正交模式和透视模式),宽高比,后处理效果等。

    而CameraActor的作用更为简单,就是将CameraComponent组件封装到一个Actor里面来使其可以直接放到一个Level里面。

    图2-2Mods里面可以放置Camera

    CameraComponent组件里面还包括另外两个组件,一个是UDrawFrustumComponent,另一个是UStaticMeshComponent。UStaticMeshComponent大家很好理解,用来渲染Actor的对象模型,而UDrawFrustumComponent是用来显示摄像机视窗的。(图1-1的紫框,只在编辑器下有)。

    2.2 PlayerCameraManger

    从名字上理解,我们可以叫他为摄像机管理器,那么他管理的是什么?答案就是视点POV。POV位置真正的计算过程是在这里进行的,你可以在这里处理不同人称视角的POV计算流程,处理摄像机震动与碰撞,也可以对摄像机增加镜头粒子特效(溅血效果等)。

    2.1.1 ViewTarget

    顾名思义,即观察目标,也就是我们想让摄像机跟随的对象。对于一般的第三人称游戏,我们的摄像机一直是对准着我们控制的角色的,这个角色可以认为就是ViewTarget(不过ViewTarget不仅仅是一个Actor)。ViewTarget定义在PlayerCameraManager里面,负责提供给Manger一个理想的POV。一个ViewTarget结构包含一个Actor对象,该Actor对应的POV信息以及当前的PlayerState。换句话讲,我们一般通过ViewTarget包含的Actor的位置来计算摄像机POV的位置,并把计算后的结果再存储到ViewTarget里面的POV。

    图2-3ViewTarget内部结构

    2.3 CameraComponent,CamerActor与PlayerCameraManger

    经过前面的介绍,我们知道PlayerCameraManager通过绑定一个ViewTarget来计算POV的位置。一般来说,我们将CameraComponent放进的Actor就是我们理想的ViewTarget。同理,拥有CameraComponent的CameraActor也同样是ViewTarget。

    PlayerCameraManager一般有几个摄像机模式(CameraStyle),如下图


    而在构造时他默认的模式是另一个

    默认模式下,PlayerCameraManager在更新POV的时候会调用Actor的CalcCamera。CalcCamera先判断是否有CameraComponent并且bFindCameraComponentWhenViewTarget是否为true,是的话就获取CameraComponent的位置与朝向,否则就获取VIewTarget的Actor的坐标与朝向来更新视点POV的信息。

    而其他的模式需要玩家去进一步做详细的计算。

    如果当前的ViewTarget是一个CameraActor的话,PlayerCameraManager就会直接获取CameraComponent的位置与朝向来更新POV。

    2.4 PlayerController与PlayerCameraManger

    我们知道,在UE4里面每个Pawn都会有一个对应的Controller,我们自然想让Controller拥有控制Rotation(朝向)的功能(为什么不控制Location?因为Location跟随Viewtarget就可以了)。所以这里有一个UpdateRotation函数来控制朝向。那么他是如何影响到PlayerCameraManager里面对视点的计算呢?

    我们可以再回头看一下图2-1,通过观察,我们可以看到一个PlayerController里面有一个PlayerCameraManager属性。当我们旋转鼠标时,这个偏移量会通过AddControllerYawInput与AddControllerPitchInput传入RotationInput。在PlayerController执行UpdateRotation时会获取PlayerCameraManager并通过ProcessViewRotation计算出移动后(也就是将RotationInput计算进去)的Rotation,把这个Rotation赋值给ControlRotation以及Controller所控制的Pawn(也就包括他身上的CameraComponent组件)。

    图2-4Controller接收鼠标旋转流程

    最后,经过上面流程,我们的CameraComponent朝向已经被修改,PlayerCameraManager在更新POV的Rotation时获取CameraComponent的朝向即可。(这个就是UE4默认情况下的摄像机处理流程)

    假设我们没有任何CameraComponent组件呢?这其实也很简单,在图2-1可以看到一个PlayerCameraManager类会有一个PlayerController属性,这样PlayerCameraManager就可以随时获取当前ViewTarget对应的PlayerController。而且我们在图2-4的流程里面其实已经通过SerControlRotation的获取了当前摄像机计算后的朝向,所以在PlayerCameraManager更新POV朝向的时候,获取Controller的ControlRotation既可。这样,我们在更新POV朝向的时候就不需要获取CameraComponent的朝向了,没有借助任何CameraComponent或是CameraActor。

    注:我们看到图2.4里面最后的两步是处理角色朝向的。经过该图里面的处理,玩家会随着摄像机的旋转而旋转。但是目前很多流行的游戏是通过玩家方向键来控制朝向的。

    三.总结与梳理

    通过上面的介绍,我们基本上了解了摄像机相关类之间的关系。这里再重新梳理一下,

    如果我们想实现摄像机的控制,有两个基本方案。

    方案一、UE4官方教程,将一个CameraComponent放到我们想控制目标的身上。然后通过获取摄像机组件的位置与朝向更新POV。

    方案二、控制的目标可以任意,Viewtarget身上没有CameraComponent。PlayercameraManager通过获取ViewTarget的位置+一定的偏移(PlayerCameraManager有一个TPVCameraOffset和一个FreeCamOffset)来确定POV的位置。而对于朝向,PlayerCameraManager通过获取PlayerController的ControlRotation既可。

    我们要知道,PlayerCameraManager这里的计算其实是偏底层一些的。有的时候我们不需要去修改这里的计算也可以处理一些摄像机的设置,比如旋转角度限制,自定义的计算POV朝向这些可以写在PlayerController的CalcCamera里,并在UpdateCameraRotation里面调用。总而言之,我们需要弄清的就是视点POV的位置与朝向到底是如何计算的。

    最后再总结一下,摄像机POV计算的要点有两个

    一、 你要保证你的计算过程是在Update里面进行的

    二、 你要在PlayercameraManager计算POV的时候能获取到你更新后的位置与旋转

    有了上面两个条件,你就可以平滑的更新POV的位置与朝向了。

    注:到这里,我们已经发现了两个CalcCamera,一个在Actor里面,是用来获取Actor或者他身上的CameraComponent组件位置与朝向的。另一个是PlayerController里的,用来进行自定义对摄像机POV进行处理计算的,默认是不调用的。

    图3-1摄像机更新视点POV流程


     

    四摄像机使用细节

    .

    4.1 摄像机位置处理

    2.4节我们简单提到过一种摄像机的使用流程。游戏初始化后,PlayerCameraManager会把玩家角色的Pawn设置为ViewTarget,然后获取ViewTarget的坐标作为一个基础值。基础值加上玩家身上的CameraOffset就得到了视点POV的位置。不过这里的CameraOffset是相对于ViewTarget局部坐标系的偏移,还要根据当前的角色的朝向以及Mutiplier来做进一步处理。

        如果想让玩家在不同状态下调整不同的视角,可以增加多个CameraOffset(如果射击CameraOffset)。然后在不同的状态下切换不同的CameraOffset即可。

    4.1 摄像机FOV处理

    在很多游戏里面,如果使用弓箭,枪一类的武器,可以进行瞄准。瞄准的实现方法就是修改摄像机的FOV。可以在武器上设置一个OverrideFOV属性,通过在瞄准时更新当前的FOV可以实现瞄准的效果。

    五.摄像机特殊处理




    5.1 摄像机震动

    图5-1摄像机调整相关类图

        这里我们把摄像机相关类图再拿出来看一下。观察到有一个继承于UObject的UCameraModifer类,他的作用就是对摄像机进行相关的调整,这里我们定义任意的Modify类型来继承于UCameraModifer,但实际上我们最常用的就是UCameraModifier_CameraShake(即摄像机震动),他是真正负责执行摄像机震动的类。

        在PlayerCameraManager更新POV信息的时候,或根据条件判断是否调用CamraModifier,在该类中有一个TArray<classUCameraModifier*> ModifierList;来保存当前所有的Modifier。遍历的时候如果找到Modifier就会执行对应的修改。默认情况下,引擎提供了一个CameraModifier_CameraShake的Modifier,在执行PlayerManger初始化的时候会通过APlayerCameraManager::CreateCameraModifier添加到ModifierList里面。

        同时,我们还可以看到一个UCameraShake类,这个类就是用来设置摄像机震动参数的类,包括震动时间震动幅度等。比如,在UGameplayStatics::PlayWorldCameraShake里 面。我们就需要传入一个TSubclassOf<classUCameraShake> Shake参数。PlayerController里面也有一个ClientPlayCameraShake方法让客户端去调用,里面也需要传入UCameraShake类型。其实,执行摄像机震动的基本原理就是根据传入的UCameraShake参数来添加一个FCameraShakeInstance。具体逻辑参考函数APlayerCameraManager::PlayCameraShake。


    FCameraShakeInstance是摄像机震动实例,在UCameraModifier_CameraShake里是以数组成员ActiveShakes的形式存在的。每次执行APlayerCameraManager::PlayCameraShake的时候,都会添加一个摄像机的震动实例,当震动结束后,实例会被从ActiveShakes移除。默认的相机震动UCameraModifier_CameraShake只能执行震动逻辑,并不能修改玩家的Rotation,但是CameraModifier里面预留了修改玩家Rotation的接口,UCameraModifier::ProcessViewRotation。我们可以通过修改CameraModifier的这个接口来在震动的同时调整玩家的朝向。

    在游戏里面,我们可能调用摄像机震动的情况(及实现方法)有

    1.  靠近大型NPC(在NPC的动画蓝图里面添加Notify,通知客户端执行)

    2.  开枪(在武器上绑定UCameraShake)

    3.  玩家受伤

    4.  挥动武器击中目标时(在武器上绑定UCameraShake)

    还有很多情况,根据项目需求


    5.2 摄像机镜头粒子特效

    在PlayerCameraManager类定义中我们可以看到这样一个属性,他通过在摄像机前面绑定一个粒子特效来实现滴血等效果。通过ClientSpawnCameraLensEffect_Implementation可以使用。效果如下

    图5-3CameraLensEffect实现效果

    5.3 摄像机碰撞

    摄像机的碰撞的逻辑可以写在了PlayerCameraManager的UpdateViewTarget里面(也就是更新视点POV信息的地方),他需要在最后做一个盒型的碰撞检测,如果碰到符合通道条件的物体就会更新视点的坐标。


    5.4 摄像机模式切换

       前面介绍了UE4默认提供了几种摄像机模式给开发者使用,我们常用的有自由摄像机、第一人称、第三人称等。旁观者模式是类似一种自由摄像机的模式。

    PlayerCameraManager里面在更新POV时会判断当前的CameraStyle,从而进行不同的计算,比如我们从第三人称视角切换到第一人称视角,POV相对玩家的位置就会改变(从背后变为眼睛附近)。

    有一点也要注意一下,不同摄像机的碰撞检测通道可能是不同的。


    5.5 摄像机后处理

       UE4里面的后处理可以通过两种方法完成(另一篇博客简单的介绍了后处理 UE4后处理简述。)。第一种是通过在场景里面添加PostProcessVolume,然后摄像机处于该体积内才能产生效果。第二种是在摄像机组件里面添加与设置,这样就不需要把摄像机放在某个特别的位置。前面图4-3的第一张图就是经过高斯模糊以及颜色混合的后处理效果。

    5.6 摄像机平滑与延迟Lag

    在大部分游戏中,为了得到更好的游戏体验,摄像机的移动都是平滑的。因为摄像机是在每帧都进行更新,所以我们只要保持与我们的ViewTarget固定的距离,就可以得到平滑的效果。

    但是如果我们想从当前摄像机立刻切换到另一个摄像机机位,或者我们的ViewTarget发生瞬移,这时候如果不做任何处理,摄像机就会突然的切换(有的时候这样也没什么不好)。假如我们觉得这样切换有点突然,我们只要简单的处理一下就可以了。设置一个插值,让当前的位置逐渐插值到目标位置。(FMath::VInterpTo(当前位置,目标位置, DeltaTime,速度);

    同理,如果想做一个摄像机延迟效果(就是玩家可能突然用技能走出一大段位移,为了体现效果,想让摄像机慢慢的追上玩家),也可以使用类似的方法来实现。

    如果有兴趣,可以参考一下UE4第三人称官方例程,然后找到弹簧组件,搜索EnableCameraLag属性,试试效果。当然也可以到代码里面看看他实现的细节。


    六.其他

    1.UE4里面的DoUpdateCamera会处理相机viewTarget切换,如果当前摄像机要切换到另一个就在这里处理插值与混合,这个时候就不应该调用UpdateViewTarget。要切换的对象是PendingViewTarget,混合参数为BlendParams。

    2.PlayerCameraManager是通过void APlayerController::SpawnPlayerCameraManager()生成的

    3.把CameraManager的位置与旋转与视点同步到一起。这样,我们也可以通过摄像机的Manager获取视点的相关信息。同理,把PlayerController的朝向与视点同步,我们也可以获取PlayerController的朝向来获取视点的朝向。

    4.下面流程图描述了角色是如何被PlayerCameraManger设置为ViewTarget的。

    图6-1设置玩家控制的Pawn为ViewTarget流程图

    原文链接(转载请标明):http://blog.csdn.net/u012999985/article/details/68947410

    展开全文
  • 获取摄像机: APlayerCameraManager* CurrentCamera = GetWorld()-&gt;GetFirstPlayerController()-&gt;PlayerCameraManager; 获取摄像机位置: //获取玩家摄像机位置 FVector CameraLocation; ...
  • Unreal Engine 4 物品和摄像机控制

    千次阅读 2017-07-18 22:45:27
    摄像机控制1.右键+左右拖拉 摄像机摇摆2.右键+前后拖拉 摄像机前后3.左键+前后左右拖拉 摄像机对准方向控制4.左键+WSADEQ 控制摄像机前后左右升降5....ALT+左键 控制摄像机围绕物体旋转 ALT+右键 控制摄像机与物体的...
  • 我决定分享一下我在当前项目中处理真实第一人称相机的方法。针对真实第一人称视角,目前没有太多相关的文档。因此研究一段时间过后,尤其是当前项目中我花了不少时间去解决一些存在的难题过后,我决定写一篇相关的...
  • 相机标定问题已经是比较成熟的问题,OpenCV中提供了比较全面的标定、矫正等函数接口。但是如果我想通过一张矫正好的图像,想获得原始的畸变图,却没有比较好的方法,这里讨论了点的畸变和反畸变问题。 1.问题提出:...
  • unreal4特性介绍

    2019-01-24 11:11:55
    unreal4特性介绍 原文地址: https://www.unrealengine.com/products/unreal-engine-4  unreal enginer介绍 我的UE4学习(一) 你曾想过用连线的形式来编写程序么; 你曾想过通过编辑工具...
  • 通常一个游戏的摄像机会是如下图旋转,Unreal Engine 4 也不例外: Pitch是围绕X轴旋转,也叫做俯仰角。Yaw是围绕Y轴旋转,也叫偏航角。Roll是围绕Z轴旋转,也叫翻滚角。 下图会标示的更明白: 根据Pitch旋转 ...
  • Unreal里PlayerController、Player、Character之间的关系,要理解它们之间的关系,本质是搞明白Pawn和Controller的关系。
  • UE4-控制相机移动

    2020-05-20 12:06:02
    项目中有时候会使用actor类型或者Pawn类型蓝图用来单纯控制相机移动旋转操作。(测试为Pawn类型蓝图,添加camera组件) 一、首先要在项目设置中编辑好输入轴映射(或者在蓝图中使用WSAD键分别控制设置向前,向右...
  • 参照http://blog.csdn.net/u011860814/article/details/60469441一文就可以成功地搭建unreal上的airsim项目。我跑了一个car simulation的项目,没有接入外设,是纯模拟的,具体效果如上图。  微软的这套airsim...
  • Unreal Engine 4 书籍翻译 Building an RPG with Unreal 三 第3章 探索和战斗 创建角色 接口 PlayerController The Pawn 游戏模式类 Unreal Engine 4 书籍翻译 Building an RPG with Unreal (三)好记性不如...
  • Unreal Enginer4特性介绍

    2015-08-02 20:53:48
    声明:转载说明出处!... unreal4特性介 原文地址: https://www.unrealengine.com/products/unreal-engine-4  unreal enginer介绍 我的UE4学习(一) 你曾想过用
  • AirSim is a simulator for drones, cars and more built on Unreal Engine. It is open-source, cross platform and supports hardware-in-loop with popular flight controllers such as PX4 for physi
  • UE4/玩家控制的相机

    千次阅读 2018-05-11 22:36:29
    官方教程,玩家控制的相机 USpringArmComponent和UCameraComponent类型找不到的情况,需要在PawnWithCamera.h中添加下列头文件: #include &quot;GameFramework/SpringArmComponent.h&quot; #...
1 2 3 4 5 ... 18
收藏数 349
精华内容 139
关键字:

unreal 获取相机