Home [Unity] 캐릭터에 Foot IK 적용하기
Post
Cancel

[Unity] 캐릭터에 Foot IK 적용하기

Unity Animator에서 지원하는 IK 기능을 사용했습니다.

참고 자료

b3agz의 REALISTIC Foot Placement Using IK in Unity

1. IK Pass 활성화

  • IK를 적용하려는 객체의 Animator Layer에 IK Pass를 활성화

Unity_img_09

2. 사용한 API 설명

  • SetIKPositionWeight: AvatarIKGoal에 해당하는 부분의 포지션 변환 가중치 설정 (0 = IK 이전의 원본 애니메이션, 1 = 목표)
  • SetIKRotationWeight: AvatarIKGoal에 해당하는 부분의 회전 변환 가중치 설정 (0 = IK 이전의 원본 애니메이션, 1 = 목표)
  • GetIKPosition: AvatarIKGoal에 해당하는 곳의 Position 값 반환
    (Ex. AvatarIKGoal.LeftFoot 이면, 아바타의 LeftFoot에 매핑되어 있는 곳의 Position 값)

GetIKPosition의 AvatarIKGoal 관련 추가 설명

  • 아바타 매핑
    Unity_img_10
  • Left Leg -> Foot 에 해당하는 곳
    ![Unity_img_11][Unity_img_11.png)
  • Gizmo로 그려본 모습 (파란색 구에 해당)
    Unity_img_12

3. 코드 설명

IK 적용 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 if (animator)
 {
     // Left Foot
     // Position 과 Rotation weight 설정
     animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1);
     animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, 1);

     ///<summary>
     /// GetIKPosition 
     ///   => IK를 하려는 객체의 위치 값 ( 아래에선 아바타에서 LeftFoot에 해당하는 객체의 위치 값 )
     /// Vector3.up을 더한 이유 
     ///   => origin의 위치를 위로 올려 바닥에 겹쳐 바닥을 인식 못하는 걸 방지하기 위해
     ///      (LeftFoot이 발목 정도에 있기 때문에 발바닥과 어느 정도 거리가 있고, Vector3.up을 더해주지 않으면 발목 기준으로 처리가 되어 발 일부가 바닥에 들어간다.)
     ///</summary>
     Ray leftRay = new Ray(animator.GetIKPosition(AvatarIKGoal.LeftFoot) + Vector3.up, Vector3.down);

     // distanceGround: LeftFoot에서 땅까지의 거리
     // +1을 해준 이유: Vector3.up을 해주었기 때문
     if (Physics.Raycast(leftRay, out RaycastHit leftHit, distanceGround + 1f, layerMask))
     {
         // 걸을 수 있는 땅이라면
         if (leftHit.transform.tag == "WalkableGround")
         {
             Vector3 footPosition = leftHit.point;
             footPosition.y += distanceGround;

             animator.SetIKPosition(AvatarIKGoal.LeftFoot, footPosition);
             animator.SetIKRotation(AvatarIKGoal.LeftFoot, Quaternion.LookRotation(transform.forward, leftHit.normal));
         }
     }

     // Right Foot
     animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, 1);
     animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, 1);

     Ray rightRay = new Ray(animator.GetIKPosition(AvatarIKGoal.RightFoot) + Vector3.up, Vector3.down);

     if (Physics.Raycast(rightRay, out RaycastHit rightHit, distanceGround + 1f, layerMask))
     {
         if (rightHit.transform.tag == "WalkableGround")
         {
             Vector3 footPosition = rightHit.point;
             footPosition.y += distanceGround;

             animator.SetIKPosition(AvatarIKGoal.RightFoot, footPosition);
             animator.SetIKRotation(AvatarIKGoal.RightFoot, Quaternion.LookRotation(transform.forward, rightHit.normal));
         }
     }
 }

animator.GetIKPosition(AvatarIKGoal.LeftFoot) + Vector3.up 추가 설명

Unity_img_13


4. 구현 작동 영상

This post is licensed under CC BY 4.0 by the author.