초보 코린이의 성장 일지

UE4 FK, IK 활용한 Two Bone IK 본문

언리얼

UE4 FK, IK 활용한 Two Bone IK

코오린이 2023. 2. 6. 15:25

어렵지만 더욱 심화한 작업을 시작해 볼 것이다.

본을 가상으로 만들어서 특정한 부위가 움직였을시 자연스럽게 움직일 수 있도록 만들어 보겠다.

 

하나 알고 지나가야하는게 있다. 

1. spine_01 부위에 반일 Mesh Space Rotation Blend를 끄고 몽타주 애니메이션을 UpperBody로 바꾸고 동작을 취하면
허리가 고정되어 이상하게 동작을 하게 된다.

2. 물론 x, y, z 축 값을 주면 그 수치만큼은 움직일 수 있으나 그렇게 되면 다른 수치에 영향을 주게 될 수도 있다.

3. 결국에는 Pelvis에서 회전을 90 주고 아래에 spine_01에 회전7을 줬다고 가정한다면, 움직일때 허리 부분이 90에 고정된 상태에서 7만큼 움직인다.

 

Mesh 공간이라는건 Skel Mesh 안에서 옵션으로 수정해 주는 것.

Component 공간은 실제로 Skel Mesh가 Skel Component안에 애니메이션을 수정하는 기능이있다.

 

 

1. 로컬을 컴포넌트로에서 본 트랜스폼(변경)을 사용하는 전까지는 수정이 불가능하고 그 다음부터 수정이 가능해진다.

그래서 그전에 설명한 컴포넌트에서 로컬로가 계산을 다시해주기 때문에 연산양이 엄청나게 많아진다.

2. 모든 옵션에 적용은 컴포넌트에서 로컬로 이 지점에서 일어난다.

ABP_Character 이벤트그래프

1. 예를 들어서 설명하기 위해 보여주기위한 코드를 작성한 것이다.

2. Skel_Mannequin에 만약 목 부위를 변형 시켜보겠다.

1. 보이는거와 같이 마우스에 따라 뒤로 목이 꺽이게 되는 현상이 발생한다.

2. 컴포넌트 공간을 프로그래밍으로 수정 할 수 있다는 것을 보여주기 위함이다.

3. 이걸 활용해서 총을 가진 캐릭터가 마우스 시점에 따라 값 제한을 걸어 고개를 돌아가게 하는데 쓰인다.

 

1. 2 본 IK에 보면 Effector, Joint를 좌우를 합처서 계산하는 형태로 나와있다.

2. 하지만 내가할 방법은 쪼개서 하나하나씩 합처서 넘기는 형태로 할 것이다.

3. 이게 보기에도 이해하기 편하기도 하며, 퍼포먼스 차이도 발생하지 않는다.

 

위 설명과 동일한 ANP_Character인 애니메이션 안에서 이제 작업을 진행해 보겠다.

ABP_Character에 사용 할 변수
가상 본 4개 추가

1. 백터로 계산하기 위해 핀 분활을 하여, 본 트램스폼(변경)애 연결해준다. 아직 계산하기 직전에 상태

2. IK를 계산할때 직접 Bone을 움직이는 기능이있다. 이렇게 되면 원본과 섞일시 값을 계산할 수 없는 지경에 이른다.

3. 그래서 방법이 Bone에 부위에서 가상 Bone를 만들어서 계산에 사용하면 된다. 그래서 Skel_Mannequin 아래 자세히 보면 ik라고 분리되어 있는 ik를 위한 Bone 부위들이 정해져있다. 

4. IK는 무조건 가상 Bone를 사용한다고 생각하면 된다. 그래서 계산할 위치에 가상 Bone를 생성해주면, 그 생성한 부위 사이의 값을 구해서 동작을 자연스럽게 만들 수 있다.

5. 무릎까지는 FK로 계산하고, 무릎부터 발목까지는 IK로 계산하고, 그 밑에 발바닥쪽까지는 다시 FK로 계산 할 것이다.

 

섞기 위한 가상 Foot_L
섞어 위한 가상 calf_l

 

섞어지는 위치 2 본 IK

최종으로 섞을때 이렇게 이어져 있다.

1. 각 본 설정에 Add to Existing로 되어있는 이유는 값을 더해줘서 특정한 위치만큼 이동시켜줘야 하기 때문

2. 순서는 가상공간에 부위들이 생겨나고 -> 가상 부위들에서 계산이 이뤄진다. -> 그로인해 위치에 맞게 자리를 자리잡게 된다 -> 하지만 아직 계산만 이뤄졌을뿐 최종으로 들어가는 곳은 2본 IK에서 이뤄진다.

3. 결국에 모든 값이 먹는 부위는 Foot_L이다. 그리고 Allow Stretching를 켜준다. Start, Max에 수치는 보정을 위한 수치라고 생각하면 된다.

4. 3개 Effector 설정이 다 Bone Space로 되어있는 이유는 계산한게 Bone이므로 결과물도 Bone로 받아줘야한다.

5.  2 본 IK 설정 -> Effector -> Effect Target에 설정은 처음에 위에 설정해준 본 트래스폼(변경) 첫번째 지점이 값을 변경하라고 지시해주고,  2 본에서 실제계산이 이루어진 것이다.

6. Joint Target도 위에 맞게 Bone Space 설정해주고, 본 트랜스폼(변경) 두번째 지점인 가상 부위를 설정해준다.

이 또한, 2 본 IK에서 지시받은 값으로 계산한다.

 

Replace Existing = 현재값을 무시하고 들어오는 값으로 변경되어버린다.

Add to Existing = 원래 있던 값에 들어오는 값을 더 해줘서 변경되어버린다.

Bone이 움직이게 변경하고 있으므로 Bone Space로 설정

위에 쓰는 용도가 다 나눠져있다. 추후에 설명을 하게 될 것이다.

 

1. 중간에 본 VB ik_foot_l_Foot_L은 중복이고, 본 트랜스폼에 나타나 있는 부위별로 내려온다.

2. 왼쪽 발부터 -> 오른쪽 발 -> 전달된 상태를 받아주고 마지막 2본 IK때 해줘야 할게 있다.

3. 대칭구조로 좌우를 만들었기 때문에 - 값으로 위에서 준 수치를 반대로 뒤집어줘야한다.

 

완성 상태인데 문제가 발생했다. 

1. 발이 땅에 거리를 계산해서 닿는거 까진 좋으나, 중간 지점이 짤려버리는 상태가 발생한다.

2. 이걸 해결하기 위해서는 허리 부분이 발이 내려가는 지점만큼 똑같이 내려와주면 된다.

3. 우리는 좌우 발중 낮은 위치를 가지고 있는 발을 기점으로 허리를 내려줄 것이다. 

 

 

Apply_InverseKinemetics 추가된 부

(중요)

Pelvis를 왜 또 -  를 해주는지 이해를 하지 못했다. 단순하게 생각해서 발에서 빼주면 아래로 이미 내려가는데 거기서 추가로 Pelvis를 내려주면 바닥으로 더 꺼져야 하는게 당연한거 아닌가라는 생각으로 접근을 했다. 하지만 정반대였다.

Pelvis가 이미 계산되어 들어와 저장이 되어있는 상태 -> 양발을 비교하여 더 아래에 있는 수치를 파악해 그 값만큼 더 내려준다 -> Pelvis를 이미 계산하고 발을 내렸기 때문에 발꺼짐 현상이 발생한다 -> Pelvis 내려 준 수치만큼 저장된 값에서 다시 올려준다 -> 이 과정에서 음수가 나올수도 있기 때문에 보정을 해준다 -> 발이 지면에 닿을때 꺼짐 현상이 사라지고 정상적으로 보정이 이루어진다.

 

1. 값이 적용되기전에 MIN을 사용하여 양발 중 누가 낮은지 체크를 해준다. 그 이유는 허리를 그 방향으로 내려줘야하기 때문에

2. Trace에서 Pelvis Distance Save 갈거리에서 가는 만큼 빼주고,  좌우에 맞게 허리가 알맞게 내려가야 하므로 곱해준 것
3. 허리는 Z축이므로 Pelvis Distance Save 연결

 

1. 왼쪽을 기점으로 한번 계산 -> 다시 오른쪽을 기점으로 계산 -> 그리고 내려와서 최종적으로 Pelvis인 허리에서 계산이 이뤄진다.

2. 주의할것은 위 계산은 Bone Space에서 계산했지만 나올때는 World Space에서 최종적으로 결과가 나와야한다.

이제는 자연스럽게 변경되었다.

 

또 하나의 문제가있다.  발 회전이 자연스럽지 않다.

발축이 맞지 않아서 그런 것이라서 이걸 고처줘야한다.

 

(중요)

평면에서에 x, y 축이 있다고 생각했을때 이 두 축을 cross(외적) 하면 z축이 나온다.

그러면 3차원이 생기면서 사각형이였던 각이 입체로 바뀌면서 정육면체로 바뀐다.

3D공간에서는 무조건 시계방향으로 진행된다. 그래야 정방향이 정해진다.

그게 아니라면 뒤나 다른 방향이 도출된다.

각을 내적을 했을때 두 벡터가 동일하다면 1, 두 벡터가 수직하면 0, 밑으로 내려가면 - 값이 나온다.

 

Trace 뒷 부분 추가

LineTraceByChannel에서 Trace Complex를 켜준 이유는 정밀하게 충돌을한다.

Impact Normal은 표면정보로 충돌체에 정보를 나타내며, 정밀하지 않다

그래서 Normal을 사용할 것이다.

 

1. 발이 회전하는 방향이 Y축은 아니므로 break를 선언해서 Z축만 사용할 것이다.

2. Atan과 Atan2가 있는데 Atan은 들어갈 요소를 X 분의 Y로 넣어주면 되고, Atan2 X, Y 따로 넣을수 있다.3

3. Atan2에서 X, Y가 뒤집혀 있으므로 break vector을 사용하여, Z 분의 Y를해서 연결해준다.

4. 또 Atan2를 사용하여 뒤집어져 있는 상태이므로 X -> Y로, Z -> X로 보내준다.

5. 회전공간이 뒤집어져 있으므로 -1 을 곱해주고 Y축에 연결해준다.

 

원래 있던 코드에 추가된 노드들

추가된 노드에 Trace를 각 Target에 연결한 상태

1. 회전보간은 RInterp To 이다

2. 회전은 한점에서 한점으로 가려면 선으로 가는게 아닌 회전으로 가기때문에  선형이 아닌 포물선으로 간다. 그래서 구형 공간이다.

3. 엔진에서 회전을 다루게 되면 다 사원수로 계산한다.

 

위에 식에서 연결된 RInterp To의 값이 Data Left Rotation, Data Right Rotation 자신의 짝에 들어온다.

위에 다 완료된 상테 최종 노드

 

본 트램스폰(변경)
2 본 IK

1. 이제 알맞게 들어온 값대로 넣어주기 위해 각 방향에 맞는 Feet Data Left Rotation, Feet Data Right Rotation 본 트랜스폼에 연결

2. 본 트램스폰(변경) Left, Right 다 Rotation 설정에 Add to Existing로 변경해주고, Normal로 계산됐기 때문에 World Space이다.

3. 2 본 IK에 본 트랜스폼에서 계산된 회전을 가져다가 써야하므로, Effector에 있는 Take Rotation from Effector Space를 true로 체크해준다.

 

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

 

- 이론적으로 상당한 이해를 필요로한다.

- Atan을 확실하게 이해하기

Comments