Pitch, Yaw, Roll + 3인칭

CJB_ny·2022년 12월 24일
0

UE4

목록 보기
18/20
post-thumbnail

일단 아래 링크 한번 보는거 씹추천

https://www.youtube.com/watch?v=LMvBLzlOHiI

현재

void AABCharacter::SetControlMode(int32 ControlMode)
{
	if (ControlMode == 0)
	{
		SpringArm->TargetArmLength = 450.f;
		SpringArm->SetRelativeRotation(FRotator::ZeroRotator);
		SpringArm->bUsePawnControlRotation = true;
		SpringArm->bInheritPitch = true;
		SpringArm->bInheritYaw = true;
		SpringArm->bInheritRoll = true;
		SpringArm->bDoCollisionTest = true;
		bUseControllerRotationYaw = false;
	}
}

위의 코드를 분석중인데 위의 코드를 실행을 하면은 SpringArm이 마우스의 회전에 따라 플레이어의 회전에는 영향을 주지 않고 회전을 막한다.

GTA같은 3인칭을 구현을 한 것이다.

bUseControllerRotationYaw = false;

그럼 위의 이거는 뭘까?? Yaw축으로 회전을 한다는 것을 false로 설정한다? 사용하지 않겠다라는 것을 짐작이 가능한데

위에서 내려다 봤을 때 Yaw Z축으로 마우스를 회전하면 플레이어도 같이 돈다...

https://lunchballer.com/archives/960

여기 비행기 그림 한번 참고하고

이 움짤 다시 보도록 하자.


손가락 저모양으로 하고

캐릭터 값 수정하면서 회전 시켜 보도록 하자... 이해 ㅅㅌㅊ급으로 잘되는듯?

그래서

bUseControllerRotationYaw = false;

이것은 Playercontroller의 Yaw회전을 막는것이라 유추~ 가 가능하고

bUsePawnControlRotation 이거는 한국어 블로그는 거의 죄대 코드만 있고 뭐하는건지 설명은 없는듯?

https://kid5.tistory.com/373
여기 함 읽어보셈요.

더 정확한것은

https://docs.unrealengine.com/5.1/en-US/API/Runtime/Engine/GameFramework/USpringArmComponent/
언리얼 공식

일단

bUseControllerRotationYaw = false;

이거 false로 하거나 주석처리하면 마우스의 회전에 따라 캐릭터 회전을 안함. 카메라도 회전을 안함.

Pawn의 회전을 사용을 하는 부분을 true로 켜주거나 false로 켜는 것을 말하는 함수이다.

Actor의 회전 ❗❗❗

Actor의 회전값 0, 0, 0은 그 Actor가 바라보는 방향이 월드의 X축방향 (1, 0, 0)을 의미한다.

월드의 X축 방향은 기본 회전값에 대응하는 방향 값이라고 할 수 있다. Actor가 회전하면 액터의 시선 방향도 자연스럽게 다른 값으로 변한다.

PlayerController의 회전값으로 부터 회전 행렬을 생생해서 원하는 방향축을 대입해 캐릭터가 움직일 방향값 얻을 수 있다.

UE에서 시선방향은 X축, 우측 방향은 Y축을 의미한다.

void AABCharacter::UpDown(float NewAxisValue)
{
	if (NewAxisValue == 0.f) return;
	AddMovementInput(GetActorForwardVector(), NewAxisValue);
}

void AABCharacter::LeftRight(float NewAxisValue)
{
	if (NewAxisValue == 0.f) return;
	AddMovementInput(GetActorRightVector(), NewAxisValue);
}

위와같은 코드는 카메라의 방향과 상관없이 그냥 액터의 기본 회전값(ZeroVector)가 (바로보는 방향이)월드의 X축방향 (1, 0, 0)을 의미하기 때문에 w키 누르면 앞으로 쭉간다.

GTA처럼 카메라 회전값에 맞게 움직일 수 있게 하려면 위에서 말한것 처럼

PlayerController의 회전값으로 부터 회전 행렬을 생생해서 원하는 방향축을 대입해 캐릭터가 움직일 방향값 얻을 수 있다.

이렇게해야함.

FRotationMatrix ❗❗❗

그래서 플레이어 컨트롤러로 부터의 회전값으로 부터 시선 방향과 우측 방향의 벡터값을 가져오도록 코드를 수정해야한다.

void AABCharacter::UpDown(float NewAxisValue)
{
	if (NewAxisValue == 0.f) return;
	AddMovementInput(FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::X), NewAxisValue);
}

void AABCharacter::LeftRight(float NewAxisValue)
{
	if (NewAxisValue == 0.f) return;
	AddMovementInput(FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::Y), NewAxisValue);
}

또한 Character가 자연스럽게 회전할 수 있도록 CharacterMovement컴포넌트의 기능을 사용하도록 하자.

void AABCharacter::SetControlMode(int32 ControlMode)
{
	if (ControlMode == 0)
	{
		SpringArm->TargetArmLength = 450.f;
		SpringArm->SetRelativeRotation(FRotator::ZeroRotator);
		SpringArm->bUsePawnControlRotation = true;
		SpringArm->bInheritPitch = true;
		SpringArm->bInheritYaw = true;
		SpringArm->bInheritRoll = true;
		SpringArm->bDoCollisionTest = true;
		bUseControllerRotationYaw = false;
		GetCharacterMovement()->bOrientRotationToMovement = true;
		GetCharacterMovement()->RotationRate = FRotator(0.f, 720.f, 0.f);
	}
}

중간중간 이해가 안가는 FRotationMatrix에 인자를 넣어주는 부분은

https://pppgod.tistory.com/25
이곳에서 FRotator조금 읽도록 하자.
FRotator를 실질적으로 사용을 할려면 "행렬"을 사용을 해야한다.

이후
GetUnitAxis 는

https://pppgod.tistory.com/26
여기 바로 읽도록 하자.

근데 위에부분 회전행렬 구해서 원하는 축을 찾는 코드에서

결과적으로 GetScaledAxis 는 변경된 좌표평면에서 자신이 찾고 싶은 축이 가지는 방향을 가져오는 함수이다. 위의 예제의 경우에는 X 축을 가져오게 된다. 즉 캐릭터가 바라보는 방향이다. 결과적으로 위의 코드는 현재 바라보는 방향으로 Value 만큼 이동한다는 의미가 된다.

void AABCharacter::LeftRight(float NewAxisValue)
{
	if (NewAxisValue == 0.f) return;
	// AddMovementInput(FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::Y), NewAxisValue);

	AddMovementInput(FRotationMatrix(GetControlRotation()).GetScaledAxis(EAxis::Y), NewAxisValue);
}

GetUnitAxis나 GetScaledAxis나 동작이 똑같음. 차이점은 구글링해도 안나옴..ㅠ

MakeFromX

https://chaoyue.tistory.com/270

FRotationMatrix는 회전된 좌표계 정보를 저장하는 행렬이다.

MakeFromX는
함수는 입력 파라미터 벡터를 X축으로 하여 새로운 기저를 구축하고, 그 기저로의 회전 행렬을 리턴한다.

기저로의 회전 행렬을 return한다 == 하나의 벡터값과 이에 직교하는 나머지 두축을 구해 회전행렬을 생성하고 이와 일치하는 FRotator값을 얻어오는 방식을 사용함.

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

	switch (CurrentControlMode)
	{
		case EControlMode::DIABLO:
		{
			if (DirectionToMove.SizeSquared() > 0.f)
			{
				GetController()->SetControlRotation(FRotationMatrix::MakeFromX(DirectionToMove).Rotator());
				AddMovementInput(DirectionToMove);
			}
		}
		break;
	}
}

카메라 부드럽게 전환

InterpTo

지정한 속력으로 목표지점까지 진행하되, 목표지점까지 도달하면 그 값에서 멈추는 기능이다.

SpringArm->RelativeRotation ❗

위에거 SpringAmr->GetRelativeRotation() 이렇게 바꿔주면됨 (버젼 차이 인듯)

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

	SpringArm->TargetArmLength = FMath::FInterpTo(SpringArm->TargetArmLength, ArmLengthTo, DeltaTime, ArmLengthSpeed);

	switch (CurrentControlMode)
	{
		case EControlMode::DIABLO:
		{
			SpringArm->SetRelativeRotation(FMath::RInterpTo(SpringArm->GetRelativeRotation(), ArmRotationTo, DeltaTime, ArmRotationSpeed));

			if (DirectionToMove.SizeSquared() > 0.f)
			{
				GetController()->SetControlRotation(FRotationMatrix::MakeFromX(DirectionToMove).Rotator());
				AddMovementInput(DirectionToMove);
			}
		}
		break;
	}

	switch (CurrentControlMode)
	{
		case EControlMode::DIABLO:
		{
			if (DirectionToMove.SizeSquared() > 0.f)
			{
				GetController()->SetControlRotation(FRotationMatrix::MakeFromX(DirectionToMove).Rotator());
				AddMovementInput(DirectionToMove);
			}
		}
		break;
	}
}

막 위에 코드처럼 바꾸어 주었는데 이 부분은 크게 어렵지 않은거 같다.

정리 및 후기 👍👍👍

역시나 DX를 제대로 공부 안하고 왔기 때문에 회전행렬이나 뭐 이런 부분 대충은 알지만

MakeFromX와같은 부분 나오거나 설명해주면 이해하기가 많이 어렵고 이해도 잘 안된다.

특히 회전 부분이 나는 많이 취약한거 같다.

그래도 어느정도 코드 분석하고 어거지로라도 게임 분석하면서 따라가지는 정도까지는? 되는거같은데 더 해야할듯...

FRotatorMatrix같은 함수를 써서 회전행렬로 왜 변환해야하는지는...

https://velog.io/@starkshn/Vector-Matrix#matrix 다시 보거나 강의 다시 듣자...

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글