11.19 - TIL

김혁·2025년 11월 19일

TIL

목록 보기
60/84

오늘의 코드카타

오늘의 공부

팀 프로젝트 진행 내용

1. 모션 워핑 추가

  • 파쿠르 앞,뒤 Ledge, Floor의 위치를 게임 내의 값과 맞추기 위해 모션 워핑을 추가했다.
  • 먼저 모션 워핑 플러그인과 모듈을 추가했다.
  • 이후에 몽타주에 Motion Warping Notify State를 추가했다.
  • Motion Warping Notify State의 설정 값은 몽타주마다 별도로 설정을 했는데, 주요한 내용만 보자면 attach라는 뼈 구조를 이용해서 FrontLedge 값을 맞추고 있다.
  • FrontLedge, BackLedge, BackFloor 세 가지의 Warp Target을 통해 설정해줬다.
  • 해당 내용은 GASP를 활용해서 제작했다.
  • 먼저 FrontLedge 워프 타겟을 위치와 회전 값을 지정했다.
  • 위치는 FrontLedgeLocation을 통해 손의 짚는 위치를 지정하고자 했고, 파쿠르 애니메이션과의 이동방향과 현재 이동방향을 맞추기 위해서 회전 값을 지정했다.
void UAO_TraversalComponent::UpdateWarpTargets()
{
	TObjectPtr<UMotionWarpingComponent> MotionWarping = Cast<UMotionWarpingComponent>(
		Owner->GetComponentByClass(UMotionWarpingComponent::StaticClass()));

	MotionWarping->AddOrUpdateWarpTargetFromLocationAndRotation(
		FName(TEXT("FrontLedge")),
		TraversalResult.FrontLedgeLocation + FVector(0.f, 0.f, 0.5f),
		UKismetMathLibrary::MakeRotFromX(UKismetMathLibrary::NegateVector(TraversalResult.FrontLedgeNormal)));
        
    ...
}
  • 파쿠르 타입이 Hurdle과 Vault인 경우에만 BackLedge를 활용하기 때문에 해당 경우에만 BackLedge 워프 타겟을 통해 워핑을 실행시켜줬다. (Mantle은 장애물을 올라가기 때문)
  • 해당 몽타주에 BackLedge 워프 타겟을 가지는 Motion Warping 노티파이 스테이트를 찾고, 있다면 Backledge 워프 타겟을 워핑해줬다.
  • 또한 종료 시점에 Ledge와의 거리를 정의해놓은 Curve를 통해 Value를 받아와서 이를 저장해서 BackFloor 워프 타겟을 계산할 때 사용했다.
	...
    
	if (TraversalResult.ActionType == ETraversalActionType::Hurdle
		|| TraversalResult.ActionType == ETraversalActionType::Vault)
	{
		TArray<FMotionWarpingWindowData> OutWindows;
		UMotionWarpingUtilities::GetMotionWarpingWindowsForWarpTargetFromAnimation(
        	TraversalResult.ChosenMontage, FName(TEXT("BackLedge")), OutWindows);

		if (OutWindows.Num() > 0)
		{
			UAnimationWarpingLibrary::GetCurveValueFromAnimation(
				TraversalResult.ChosenMontage,
				FName(TEXT("Distance_From_Ledge")),
				OutWindows[0].EndTime,
				DistanceFromFrontLedgeToBackLedge);

			MotionWarping->AddOrUpdateWarpTargetFromLocationAndRotation(
				FName(TEXT("BackLedge")),
				TraversalResult.BackLedgeLocation,
				FRotator::ZeroRotator);
		}
		else
		{
			MotionWarping->RemoveWarpTarget(FName(TEXT("BackLedge")));
		}
	}
	else
	{
		MotionWarping->RemoveWarpTarget(FName(TEXT("BackLedge")));
	}
    
    ...
  • 다음으로 Hurdle 동작에서만 BackFloor 워프 타겟이 필요하기 때문에 해당 경우에만 모션 워핑을 실행시켰다.
  • 위와 같이 BackFloor 워프 타겟을 가지고 있는지 확인을 한 후에, 앞에서 계산한 BackLedge 위치와 Normal 값, BackFloor 위치 값을 통해 BackFloor 타겟을 워핑했다.
	...
    
	if (TraversalResult.ActionType == ETraversalActionType::Hurdle)
	{
		TArray<FMotionWarpingWindowData> OutWindows;
		UMotionWarpingUtilities::GetMotionWarpingWindowsForWarpTargetFromAnimation(TraversalResult.ChosenMontage, FName(TEXT("BackFloor")), OutWindows);

		if (OutWindows.Num() > 0)
		{
			UAnimationWarpingLibrary::GetCurveValueFromAnimation(
				TraversalResult.ChosenMontage,
				FName(TEXT("Distance_From_Ledge")),
				OutWindows[0].EndTime,
				DistanceFromFrontLedgeToBackFloor);

			FVector TargetLocation = TraversalResult.BackLedgeLocation
				+ TraversalResult.BackLedgeNormal * abs(DistanceFromFrontLedgeToBackLedge - DistanceFromFrontLedgeToBackFloor);
			TargetLocation.Z = TraversalResult.BackFloorLocation.Z;
			
			MotionWarping->AddOrUpdateWarpTargetFromLocationAndRotation(
				FName(TEXT("BackFloor")),
				TargetLocation,
				FRotator::ZeroRotator);
		}
		else
		{
			MotionWarping->RemoveWarpTarget(FName(TEXT("BackFloor")));
		}
	}
	else
	{
		MotionWarping->RemoveWarpTarget(FName(TEXT("BackFloor")));
	}

2. Leg IK 노드 추가

  • 올라가는 파쿠르 애니메이션을 재생할 때 아래의 사진과 같이 공중에 뜨는 현상이 존재했다.
  • 발을 정확하게 벽에 맞추기 위해 Leg IK 노드를 사용했다.
  • 일반적으로는 Leg IK는 발이 땅에 파묻히거나 떠오르는 것을 막기 위해 Line Trace 결과를 기반으로 발을 지면 높이에 맞춰준다.
  • 하지만 샘플 프로젝트의 주석을 바탕으로 보았을 때는 지면 높이가 아니라, Pose Warping을 통해 이미 계산된 IK 발 위치로 고정시키기 위해 사용된다는 점을 알 수 있다. 따라서 파쿠르 동작 시에 정확한 발 부착을 위해 해당 노드를 사용했다.
  • IK Rig은 Auto Create IK를 사용해서 생성했고, 아래와 같이 손과 발에 IK 본이 생성되는 것을 확인했다.
  • 아래는 결과물로 발이 공중에 뜨는 현상을 제거한 모습이다.

알게 된 점

1. Rewind Debugger에 메시가 표시 안 되는 문제

  • Rewind Debugger를 사용하는데, 메시가 안 보이는 문제가 발생했다.
  • 전에 R&D 과정에서 샘플 프로젝트를 제작했을 때는 별도의 옵션이 필요하지는 않았다. 따라서 우리 프로젝트만의 차이점을 생각해봤는데, 우리는 플레이어 캐릭터에 메타 휴먼을 사용하고 있다.
  • 따라서 메타 휴먼과의 호환성 때문에 메시 출력이 정상적으로 되지 않나라고 생각을 했다. 하지만 자료를 찾아보니 그러한 내용은 없었다.
  • 전에 메타 휴먼 제작을 하신 팀원이 메타 휴먼의 경우에는 별도의 메시를 별도로 설정하는 것이 아니라 생성자 부분에서 머리, 몸 같이 부위를 나눠서 매핑 시켜주는 개념이라고 들었다. 이에 따라 기존의 스켈레탈 메시는 Visible을 비활성화해서 보이는 것을 꺼준다고 이를 주의해달라고 들었다.
  • 스켈레탈 메시의 Visible을 활성화해주니까 정상적으로 메시가 보이는 것을 확인할 수 있었다.
  • 메타휴먼 캐릭터 자체는 Rewind Debugger에서 출력 못 하는 것을 확인할 수 있었다.

2. Leg IK를 적용할 때, 좌표계 변환을 하는 이유

  • 위의 사진을 보면 Leg IK 노드를 적용할 때, 좌표계 변환을 하는 것을 확인할 수 있다.
  • 이는 IK 연산의 정확성과 안전성을 보장하기 위함이라고 한다.

  • Local To Component
    • IK 연산에 필요한 발의 현재 위치 정보를 Local Space에서 Component Space로 변환함
    • Component Space : 스켈레탈 메시를 기준으로 하는 절대적인 공간. IK 타겟 위치(지면 위치)와 동일한 공간으로 데이터를 맞추어 정확한 거리 및 각도 계산이 가능하게 함
  • IK 연산
    • Leg IK 노드는 Component Space의 타겟 위치를 사용하여 다리 관절(허벅지, 종아리)을 회전시켜 새로운 포즈를 만듬
    • 이 새로운 포즈는 Component Space에 기반한 변형을 포함하고 있음
  • Component To Local
    • IK 연산을 거쳐 Component Space로 조정된 최종 포즈를 다시 Local Space로 되돌림
    • Anim Graph의 다른 부분은 Local Space 포즈를 입력받아 처리하도록 설계되어 있음
profile
게임 개발자를 향해..

0개의 댓글