예측 기반 Foot IK 구현하기
들어가며
개요
"최종 결과는 문서 하단에서 확인하실 수 있습니다"
이 글에서는 예측 기반 Foot IK를 구현하는 과정에서 마주한 기술적 도전과 해결 방법을 공유합니다.
기본 애니메이션 프레임워크는 ALS(Advanced Locomotion System)를 참고했으며, 기술 방안은 《어쌔신 크리드》의 예측 기반 Foot IK 시스템에서 착안했습니다. 구현 과정에서 다른 개발자들의 아티클도 참고했습니다(링크는 문서 하단 참조).
구현 방법에 부족한 점이 있을 수 있으며, 코드 작성 방식도 완벽하지 않을 수 있습니다. 제작 과정을 기록하면서 일부 내용을 보완했기 때문에 순서나 내용에 차이가 있을 수 있으며, 몇 가지 세부 사항이나 겪었던 문제들이 누락되었을 수 있는 점 양해 부탁드립니다.
예측 기반 Foot IK란?

예측 기반 Foot IK는 캐릭터의 착지점을 예측하여 이동 경로를 계산하고, IK를 통해 발과 골반을 지형에 맞게 조정하는 기술입니다. 전통적인 IK 방식보다 유연하지만, 구현은 더 복잡합니다.
전체 단계는 다음과 같습니다: 발 데이터 준비 → 착지점 예측 → Pelvis 데이터 계산 → 발 경로 계산 → 발 데이터 계산 → 데이터 적용.
데이터 준비와 예측
데이터 준비
이 단계에서는 애니메이션에 커브를 추가하여 발이 착지하기까지 남은 시간을 알려주는 값을 설정해야 합니다.
하지만 유비소프트가 강조했듯이 "반드시 자동화되어야 합니다(Absolutely must be automated)".
따라서 UE의 AnimationModifier를 사용하여 커브를 자동 생성했습니다.
애니메이션 정보를 샘플링하여 현재 프레임 정보를 획득합니다.

그런 다음 발의 높이(더 세밀하게는 발끝이나 회전까지 포함 가능)를 통해 키 포인트 여부를 판단하고 기록합니다. FootName과 Height 임계값을 파라미터로 개방했습니다.
발 위치를 얻는 직접적인 함수는 없기 때문에, 먼저 GetAnimPosAtTime을 호출한 후 GetBonePose로 획득해야 합니다.
최후에 발이 내려가는 키 포인트와 발이 올라가는 키 포인트를 연결하여 커브를 생성합니다.
착지점을 찾는 것은 간단하지만, 커브 생성에서 몇 가지 문제가 있었습니다.
여기서 시작점과 끝점의 연속성에 주의해야 하며, 커브는 선형(Linear)으로 설정해야 합니다.
최종적으로 자동 생성된 커브를 얻을 수 있습니다.

발 착지 예측
시작하기 전에 구조체를 생성하여 많은 파라미터를 넣었습니다. 이렇게 하면 나중에 수정할 때마다 함수 입력을 변경하고 수많은 파라미터를 추가하지 않아도 됩니다.

PreDictFootLocation에서는 앞서 생성한 발 착지 커브와 캐릭터의 이동 속도를 통해 착지점을 획득합니다(검은색 박스 제외).

검은색 박스 부분은 주로 발의 상대 위치 문제를 해결하기 위한 것입니다.
단일 애니메이션만 사용한다면 상대 위치를 하드코딩할 수 있습니다.
하지만 게임에 적용할 경우, 각 애니메이션의 발 상대 위치가 다릅니다.
처음에는 실시간으로 발 위치를 계산하면 되지 않을까 생각했습니다.
그러나 발은 뒤에 있을 때와 앞에 있을 때가 있으며, 착지 시에는 캐릭터의 이동을 따라가지 않습니다. 실시간 위치를 사용하면 예측 위치가 부정확해질 수밖에 없습니다.
따라서 착지 시 상대 위치를 기록한 후, 검은색 박스의 방법으로 계산하는 방식을 채택했습니다.
발이 착지했는지는 이전 프레임의 상태를 기록하는 파라미터로 판단합니다. 이전 프레임에 이미 착지했다면 데이터를 업데이트합니다. 같은 방식으로 발이 들리는 순간도 획득할 수 있습니다.
발이 착지할 때, 발의 상대 위치, 발의 시작 위치(현재 발 위치로 설정), 이전 종료 위치 등의 정보를 기록합니다.
이렇게 발의 시작 위치를 얻을 수 있습니다.
종료 위치는 BoxTrace로 실시간 획득합니다.
여기서 작은 문제가 있습니다: 예측된 착지점에 오차가 있어, 이동 시 매우 느리게 캐릭터 쪽으로 접근합니다(아래 영상 슬로우 모션 참조).
이 문제는 큰 영향은 없지만, 발이 플랫폼 가장자리에 매우 가까울 때 떨림이 발생합니다.
애니메이션, 커브, 캐릭터를 모두 확인했지만 원인을 찾지 못해 일단 그대로 두었습니다.
최종적으로 DebugShape을 통해 다음과 같은 효과를 얻을 수 있습니다:
Pelvis 데이터 계산
Pelvis 시작점과 종료점
다음으로 Pelvis를 계산합니다. 먼저 양발 사이의 시작점 위치(녹색 선)를 획득해야 하며, 이것이 Pelvis 계산의 시작점과 종료점이 됩니다.

시작점과 종료점의 전환은 발이 교차할 때 발생합니다.
양발의 Y값을 비교하여 어느 발이 더 앞에 있는지 판단합니다. 판단 결과가 이전 프레임과 다를 때 전환이 발생한 것이므로, 이때 양발 위치를 업데이트합니다.

주의사항: 종료점은 발이 착지할 때 지속적으로 업데이트되어야 합니다. 앞서 언급했듯이 착지점에 오차가 있어 점차 캐릭터 쪽으로 접근하기 때문에, 특정 프레임의 데이터만 사용하면 맞지 않습니다. 따라서 Pelvis의 착지점도 발이 착지할 때 계속 업데이트해야 합니다.
일부 애니메이션은 짧은 시간 내에 두 번 교차할 수 있어(예: ALS의 스프린트 동작) 잘못된 판단을 초래합니다. 따라서 전환에 짧은 쿨다운 시간을 추가해야 합니다.
완료 후 아래 영상의 녹색 곡선을 얻을 수 있습니다.
하지만 경사로를 오르내릴 때 Pelvis가 콜리전 볼륨을 따라 계속 움직이는 것을 볼 수 있습니다.
우리가 원하는 것은 오르막에서 착지 시 상승하고, 내리막에서 하강하면서 내려가는 것입니다.
따라서 먼저 Pelvis를 고정한 후 변위를 추가해야 합니다.
오르막과 내리막 처리
Pelvis를 고정하는 방법으로 처음에는 PelvisOffset을 사용해봤지만, 업데이트 타이밍이나 순서 문제 때문인지 1프레임 지연이 발생하여 심한 떨림이 생겼습니다.
따라서 최종적으로 채택한 방법은 캐릭터의 Mesh 높이를 직접 Set하여 항상 StartPos에 유지하는 것입니다(검은색 박스는 나중에 설명).

이제 다음과 같은 효과를 얻을 수 있습니다.
캐릭터가 시작점과 동일한 높이를 계속 유지하는 것을 볼 수 있습니다.
이후 오르막과 내리막의 로직을 처리하여(평지는 오르막/내리막으로 간주 가능) Pelvis Additive Offset Target을 계산합니다.
오르막은 착지 후 샘플링해야 하며, 종료 후 Mesh가 새로운 시작점으로 상승하므로 Additive가 0이 되어야 합니다. 그렇지 않으면 기존 기준에서 한 단계 더 높아집니다.
내리막은 발이 착지하기 전에 샘플링해야 합니다. 발이 착지한 후 양발이 아직 교차하지 않았을 수 있고 시작점도 업데이트되지 않았으므로, Additive를 마지막 지점으로 유지해야 합니다. 그렇지 않으면 다리가 교차할 때 떨림이 발생합니다.

계산 방법을 알았으니 이제 샘플링 문제를 해결해야 합니다. 여기서 StartFootRate와 EndFootRate를 미리 계산했습니다(Rate는 비율을 의미).
커브 값으로 샘플링을 시도했지만 충분히 정확하지 않았고 다른 문제도 있어 커브를 사용하지 않았습니다.
먼저 EndFoot는 내리막 샘플링에 사용됩니다.
발이 교차할 때 EndFoot는 이미 들려서 일정 거리를 이동한 상태입니다(아래 그림의 왼발).
교차 시 발 위치에서 마지막 지점 위치까지의 비율(XY 방향 길이)을 기록하여 설정합니다.


StartFootRate는 비교적 간단합니다. 교차 시 StartFoot가 착지 상태이므로, StartPos까지의 거리와 End까지의 거리를 직접 계산하면 됩니다.
마지막으로 Mesh 오프셋 부분의 Additive를 더하면 아래와 같은 효과를 얻을 수 있습니다.
Foot 경로 데이터 계산
FootPath
계산 과정은 간단합니다. 한 발의 시작점과 종료점을 초기점으로 사용합니다.
시작에서 종료로, 종료에서 시작으로 각각 레이캐스트를 실행합니다. 충돌이 감지되면 상단에서 하단으로 BoxTrace를 실행하여 충돌점을 찾습니다.
이 두 개의 새로운 점을 다음 시작점과 종료점으로 사용하며, 충돌이 발생하지 않거나 반복 횟수 상한에 도달할 때까지 반복합니다.
마지막으로 모든 점을 순서대로 결합하여 시작점에서 종료점까지 배열에 넣습니다.

이 점들을 얻은 후, 나중에 샘플링하기 위한 데이터를 준비해야 합니다.
발이 언제 이 점이 필요한지 알아야 합니다.
여기서도 예측 커브를 사용해봤지만 충분히 정확하지 않았고 문제가 있어, 위의 Pelvis 샘플링과 동일한 방법을 채택했습니다.
각 점에서 시작점까지의 거리 비율을 기록합니다. 시작점은 0, 종료점은 1, 중간 점은 0과 1 사이입니다.
최종적으로 FootPath의 월드 좌표를 기록한 배열과 Foot Curve Vars 배열을 얻게 됩니다.

FootPath 샘플링
위의 데이터를 계산한 후, 캐릭터가 현재 어떤 점을 사용해야 하는지 결정해야 합니다.
먼저 캐릭터의 발이 어떤 두 경로점 사이에 있는지 확인합니다.
그런 다음 캐릭터의 발에서 이 경로 구간의 시작점과 종료점까지의 거리 비율에 따라 보간하여 위치 정보를 획득합니다.
아래 영상에서 흰색 구체가 샘플링된 위치입니다.
Foot 적용 및 IK 문제 수정
Foot
Foot의 경우에도 현재 발 위치에서 위와 아래로 레이캐스트를 실행하여 충돌점을 통해 Trace된 발 위치를 얻어야 합니다.
이 Trace 위치와 현재 경로 샘플링 위치를 비교하여 더 높은 것을 선택합니다. 이렇게 하면 발이 벽을 뚫지 않도록 보장할 수 있습니다.
IK 위치를 얻은 후 오프셋을 계산해야 하는데, 여기서는 지면까지의 거리로 계산해야 하며 발 위치로 하면 안 됩니다. 그렇지 않으면 발의 애니메이션 움직임 디테일이 IK에 의해 덮여버립니다.
마지막으로 위치와 회전을 스무딩하면 됩니다. 이 시점에서 실행해보면 평지는 기본적으로 정상이지만, 오르막과 내리막에서 이상한 현상을 발견할 수 있습니다.
따라서 이후 Pelvis 보정이 필요합니다.
Pelvis 보정
오르막에서 발이 눌리는 문제는 Pelvis가 현재 예측 착지점을 엄격하게 따르기 때문입니다. 오르막에서 발이 올라가기 시작하기 전에는 높이가 변하지 않습니다(경사가 가파르면 지면을 뚫고 들어가기도 함).
따라서 추가 높이가 필요합니다.
채택한 전략은 Pelvis가 가장 낮은 발의 오프셋보다 낮아지지 않도록 하는 것이며, 이렇게 하면 오르막에서 정상적으로 동작합니다.
하지만 이동 속도가 빠를 때 앞발이 높이 올라가면 비정상적인 상황이 발생할 수 있습니다.
따라서 Pelvis는 앞발의 각도에 따라 일정한 오프셋을 추가해야 합니다.
다만 더 높은 발을 기준으로 조정하면 평지와 내리막에 영향을 미치므로 특수 처리가 필요합니다.

기타 발 문제 수정
이제 완벽하다고 생각하시나요?
아니, 그렇지 않습니다.
실행해보면 다음과 같은 현상을 볼 수 있습니다.

Twist가 다시 깨졌나요?
본을 열어보면:

원인은 Mesh를 아래로 내렸을 때 Root도 따라 내려가고, 몸통 부분은 Pelvis를 따라 정상으로 복구되지만 Root는 움직이지 않아 Knee에 문제가 생긴 것입니다.
따라서 이때 Knee에도 발의 오프셋을 추가로 적용해야 합니다.
이제 기본적으로 완성되었습니다.
다른 이동 상태와의 융합
다른 상태와의 융합
이 PredictIK는 달리기와 걷기에서는 잘 작동합니다.
하지만 점프, 정지 등을 추가하면 예상치 못한 문제가 발생합니다.
또한 캐릭터가 막 출발할 때 예측 IK의 일부 데이터가 완전히 업데이트되지 않아 문제가 있습니다.
따라서 정지 시에는 일반 IK를 선택하고, 공중에서는 IK를 취소하기로 했습니다.

이제 달려보면 다음과 같은 문제를 발견할 수 있습니다.
이상한 떨림
여기서 떨림은 영상의 점프 후 떨림과 이동을 시작할 때의 떨림을 포함합니다.
공중 떨림의 원인: 착지 후 일반 IK를 사용할 때 Predict의 FootLocation이 업데이트되지 않습니다. PredictFootIK로 전환할 때 발 위치가 여전히 점프 위치에 머물러 있어 떨림이 발생합니다.
해결 방법은 일반 IK 사용 시에도 Foot의 Location 계산을 업데이트하는 것입니다(글 초반 두 번째 부분의 발 예측).
또한 오르막에서 점프하면 캐릭터가 벽 속으로 떨어집니다.
원인은 Mesh를 변위시켰는데, 다시 전환할 때 Offset은 없어졌지만 Mesh 위치가 복원되지 않아 이런 상황이 발생하는 것입니다.
따라서 Reset 시 Mesh 위치를 복원해야 하지만, 보간을 추가해야 순간이동이 발생하지 않습니다.
동시에 시작 시 떨림을 해결하기 위해 Pelvis의 앞뒤 발 위치를 Actor 위치로 Reset해야 합니다(충분히 정확하지는 않지만 실제 사용에는 영향 없음).
서 있을 수 없는 문제
절벽 가장자리에 도달하면 양발의 예측이 모두 충돌점을 감지하지 못하거나 한쪽 발만 문제가 발생할 수 있습니다.

해결 방법: PredictFoot 시 충돌점이 예측되지 않으면 PredictFootIK를 실행하지 않고 일반 IK로 전환합니다.
하지만 직접 전환하면 문제가 있어 IKOffsets를 리셋해야 합니다.

세부 사항 보완
카메라 Z축 Lag를 느리게 조정한 후 떨림이 크게 개선되었습니다.
해결 대기 중인 문제와 최종 결과
최종 결과
여전히 몇 가지 문제가 남아 있지만, 최종 결과는 다음과 같으며 전체적으로 양호한 표현을 보입니다.
업데이트: 계단을 내려갈 때 레이캐스트 감지 높이 설정이 부족하여 충돌점을 감지하지 못하는 경우가 있어 PredictIK가 트리거되지 않습니다(시연 영상에 이 문제가 존재). 감지 범위를 늘려 해결할 수 있지만, 범위가 너무 크면 안 됩니다.
개선 대기 중인 문제
A. 등반 불가능한 경사로 문제
너무 가파른 경사로의 경우, Pelvis가 착지 후에야 상승하지만 발은 최저 높이(예측된 경로)를 유지하여 이상한 현상이 발생합니다.

이 문제를 해결하려면 많은 추가 상황을 처리해야 합니다. 게임에서는 자동 점프 또는 등반으로 해결할 수 있을까요? (농담이니 재미로만 봐주세요)
B. 간헐적 발 이상
이동 중 매우 낮은 확률로 발이 이상하게 움직이는 경우가 있습니다. 피곤해서 수정하지 않았습니다. 어차피 낮은 확률이니까요.
C. 예측 착지점 오차
예측 발 착지점에 오차가 존재합니다(앞서 언급).
따라서 발이 가장자리에 착지할 때 오차로 인해 안쪽이나 바깥쪽으로 치우치면 약간의 떨림이 발생합니다.
D. 스무딩으로 인한 약간의 부유
오르막과 내리막에서 발을 전환하는 과정에서 시작점이 변경되어 Mesh 높이가 바뀝니다.
점프를 피하기 위해 스무딩 처리를 추가했습니다.
하지만 이 스무딩으로 인해 발이 약간 부유하는 현상이 발생합니다.
슬로우 모션이 아니면 거의 보이지 않아 그냥 두었습니다.
참고 자료
Fitting the World: A Biomechanical Approach to Foot IK
www.gdcvault.com/play/1023009/Fitting-the-World-A-Biomechanical
Fitting the World: A Biomechanical Approach to Foot IK
Traditionally foot IK solving has been implemented by reacting to changes within the environment's physical setup. But this is often associated with either sluggish responses to very snappy/jerking motion on the knees and distinctly procedural...
www.gdcvault.com
이 글은 메이즈라인 주식회사의 기술 연구를 위해 “Shadow”님의 블로그 포스팅을 바탕으로 번역되었습니다.
https://zhuanlan.zhihu.com/p/679650155?share_code=1jjzGTzNcqBsL&utm_psn=1961734372563591967
'TECH.ART.FLOW.IO' 카테고리의 다른 글
| [번역] UE5 Shell-Fur 모발 렌더링 구현 (0) | 2025.10.23 |
|---|---|
| [번역] UE5 머티리얼에서 렌더링 파이프라인 텍스처 접근하기 (1) | 2025.10.20 |
| [번역] 언리얼엔진5 SceneViewExtension을 사용하여 Gbuffer 데이터 수정하기 (0) | 2025.10.14 |
| "Advanced Horse IK Solution" related of tech for Study lists. (0) | 2025.10.13 |
| [번역] UE5 Virtual Assets 가용성 분석 (0) | 2025.10.12 |