Game Develop

[UE5] 월드방향벡터를 캐릭터의 로컬방향벡터로 변환시키고 어떤 방향인지 알아내기 본문

UnrealEngine5/이것저것

[UE5] 월드방향벡터를 캐릭터의 로컬방향벡터로 변환시키고 어떤 방향인지 알아내기

MaxLevel 2024. 11. 8. 18:27

  
컨트롤러는 전방을, 캐릭터는 왼쪽을 바라보고 있다고 가정.

캐릭터는 전방기준으로 8가지방향에 대해 구르는 몽타주가 있다.

캐릭터는 왼쪽을 바라보고 있는데 키입력을 D키 누르고 구르기를 시도한다면, 캐릭터는 어떤 몽타주를 재생해야하는가?

오른쪽으로 굴러야하니 오른쪽으로 구르는 몽타주?
아니다. 위치이동은 키입력의 월드방향벡터로 하는게 맞지만, 몽타주는 오른쪽으로 구르는 몽타주가 아니라 뒤로 구르는 몽타주를 재생해야 자연스럽다.

왜? 캐릭터는 왼쪽을 바라보고 있으니까, 뒤로 굴러야 오른쪽으로 이동하는것처럼 자연스러워진다.

그러면 컨트롤러기준의 키입력방향벡터가 캐릭터의 로컬기준으로 어디방향인지를 알아내기 위해서는, 먼저 키입력방향벡터를 캐릭터의 로컬방향벡터로 변환해줘야 한다.

 

그러면 먼저 키입력방향벡터를 알아내보자.

여기서 말하는 키입력방향벡터란, 컨트롤러의 전방을 기준으로 대각선포함한 8가지방향에 대한 월드방향벡터를 말하는 것이다.

 

친절한 코드는 아래와 같다.

FVector AMainPlayer::GetControllerKeyInputDirectionVector(const int32 keyInputDirection) const
{
	// keyInputDirection == 0 ~ 7까지의 8방향. 전방 ~ 좌상.
	const float controllerYaw = GetController()->GetControlRotation().Yaw + 45.0f * keyInputDirection;
	const FRotator rotation = {0.0f, controllerYaw, 0.0f};
	
	return rotation.Vector();
}

 

매개변수인 keyInputDirection은 알아서 받아오면 된다.

나같은경우 전방부터 시계방향 돌리면서 각각 0 ~ 7의 인덱스를 부여해서, 수평이동값,수직이동값에 따라 방향에 맞게 가져오게 했다.

그래서 keyInputDirection값이 0이면은 전방방향벡터 (즉 컨트롤러가 바라보고 있는), 2면은 오른쪽벡터다.

언리얼에서 FRotator의 각 축의 값들 계산은 Degree이기 때문에 인덱스값 * 45.0f가 작동한다.

리턴할때는 rotation.Vector. 우린 벡터가 필요하니까.

 

키입력방향벡터를 구했으니, 이걸 캐릭터의 로컬로 재배치해줘야 한다.

그러기위해서 캐릭터의 트랜스폼의 역행렬을 키입력방향벡터에 곱해준다. 그러면 월드기준 키입력방향벡터는 캐릭터의 로컬방향벡터로 재배치된다.  ( WVP변환할때도 월드매트릭스에 뷰매트릭스, 즉 카메라트랜스폼의 역행렬을 곱하는걸 생각하면 된다)

 

재배치된 로컬벡터가 8방향중 어떤방향인지에 대해 검사해주면 끝이다.

아래가 전체코드.

 

int32 AMainPlayer::GetLocalDirection(const FVector& otherDirectionVector) const
{
	const FVector localDirection = GetActorTransform().InverseTransformVector(otherDirectionVector);
	const float radian = FMath::Atan2(localDirection.Y, localDirection.X);

	constexpr float range = PI / 8; // 22.5도

	if (radian >= -range && radian < range) // 앞쪽
	{
		return 0;
	}

	if (radian >= range && radian < 3 * range) 
	{
		return 1;
	}
	
	if (radian >= 3 * range && radian < 5 *	range) // 오른쪽
	{
		return 2;
	}

	if (radian >= 5 * range && radian < 7 * range) 
	{
		return 3;
	}

	// if ((radian < -7 * range && radian >= -8 * range) ||
	// 	(radian >= 7 * range && radian <= 8 * range)) // 뒤쪽
	// {
	// 	return 4; 
	// }
	
	if (radian < -5 * range && radian >= -7 * range) 
	{
		return 5;
	}

	if (radian < -3 * range && radian >= -5 * range) // 왼쪽
	{
		return 6;
	}
	
	if (radian < -range && radian >= -3 * range) 
	{
		return 7;
	}
	
	return 4;
}

 

함수의 첫라인을 보면 InverseTransformVector 함수호출을 통해, 액터의 역행렬과 키입력방향벡터를 곱해주는걸 볼 수 있다. 

로컬벡터는 구했으니, 이 로컬벡터가 캐릭터 전방기준으로 어디방향인지만 알아내면 된다.

그러기위해 Atan2함수를 이용해 현재 방향벡터가 이루는 각도를 라디안값으로 받아온다.

이 라디안값은 -pi ~ pi범위의 각도를 라디안값으로 반환해준다.

우리는 8방향에 대해 검사해야하니, 각 8방향에 대해 양옆 22.5도씩, 즉 pi/8씩 검사해서 범위안에 들면 해당방향이라고 인지시키면 된다.

 

뒤쪽코드 주석처리해놓은건, 저렇게 해도 되긴하는데 어차피 7개 검사하면 남은건 하나밖에 없으니 그냥 마지막에 return 4 시켰다.