smpl-x에서 motion feature를 추출할 방법을 찾다가...굉장히 유용한 코드를 찾게 되었다!!!!
https://github.com/KosukeFukazawa/CharacterAnimationTools#13-load-animation-from-amass
bvh, smpl+h의 파일을 업로드하면, Animation 객체로 만들어 motion feature를 추출할 수 있다. 여기에는 각 joint의 global position, root local position, character local position, global orientation 등이 포함되며 각 joint의 positional velocity, rotational velocity 정보도 읽어올 수 있다.
(* character local position: root를 땅으로 projected한 점을 원점, root의 direction을 땅에 projected한 방향을 z축, global y축을 y축으로 가지는 좌표계에 대해 나타낸 position)
Animation 객체를 bvh 파일 형태로 export하는 것도 가능하다. 내가 가진 smpl-x 파일을 smpl+h 형태로 변환한 뒤 Animation 객체를 생성하고 export 해보았는데, 시각화 결과 bvh export도 매우 잘되는 것을 확인했다.
위의 코드를 쓰면서 알게 된 부분들을 이제 하나하나 정리할 예정이다.
1. 뽑아온 motion feature 순서는 코드에서 사용하는 JOINT_NAMES 순서와 다르다.
생성된 Animation의 joint_names를 출력해보면 ['pelvis', 'left_hip', 'right_hip', 'spine1', 'left_knee', 'right_knee', 'spine2', 'left_ankle',...]과 같은데(넓이 우선 탐색 느낌) ,
Animation 객체로부터 motion feature를 읽었왔을 때의 joint 순서는 pelvis, left_hip, left_knee, left_ankle, left_foot, right_hip....(깊이 우선 탐색 느낌)과 같이 bvh 파일에서 나오는 joint 순서와 동일한 것 같다.
(아님. global position의 경우 넓이 우선 탐색으로 return 됨)
2. 위의 코드를 사용하여 bvh format으로 Animation을 export할 때, rest pose가 정상적으로 잘 세팅된다.
가끔 bvh로 export할 때 rest pose가 요상하게 세팅되는 경우가 많다. 위의 코드를 사용했을 때는 rest pose가 t-pose 모양으로 잘 세팅되는 것을 확인할 수 있었다.
3. smpl+h파일을 사용하여 Animation 객체를 생성할 때 손 joint를 없앨 수 있다.
smpl+h파일을 사용해서 Animation 객체를 생성할 때 load_hand 옵션을 사용하여 손 joint를 없앨 수 있다. load_hand의 기본값은 True로, load_hand가 True로 설정되어있을 경우, Animation 객체의 joint 개수는 52개, False로 설정할 경우 Animation 객체의 joint 개수는 24개로 설정된다.
(참고로, smpl+h의 joint 개수가 52개, smpl의 joint 개수가 24개이다.)
나의 경우 body joint 정보만 필요해서 손 joint를 manual하게 제거하려고 했었기 때문에 이 기능이 굉장히 유용했다.
4. Animation 객체로부터 읽어올 수 있는 정보 및 그가 의미하는 바는 다음과 같다.
- parents: parent joint의 index, pevlis joint의 경우 parent가 없기 때문에 parents의 0번 인덱스는 -1로 세팅되어있다.
- joint_names: joint의 이름. 너비 우선 탐색 순서로 출력된다. (['pelvis', 'left_hip', 'right_hip'...])
- offsets: (parent에 대해 표현된) rest pose에서의 joint position 정보, bvh 파일에서 hierarchy section의 offset 값들이 그대로 담겨있다고 생각하면 될 것 같다.
<4-1.Rotation value>
- grot: 모든 joint의 global orientation, quaternion 값으로 표현되어 있다. 이때 quaternion의 표현 순서는 (w, x, y, z)이다. (scipy의 quaternion의 경우 (x, y, z, w) format으로 표현되어 있다.)
- crot: projected root centric rotations으로으로, quaternion (w, x, y, z)로 표현되어 있다.
***아래의 4개는 같은 회전을 의미한다. format만 다르다.***
- xform: parent joint에 대해 표현된 local orientation으로, 3*3 matrix 값으로 표현되어 있다.
- axangs: parent joint에 대해 표현된 local orientation으로, axis angle form으로 표현되어 있다.
- ortho6ds: parent joint에 대해 표현된 local orientation으로, 6d rotation representation으로 표현되어 있다.
참고로 quaternion 형식으로 표현된 값들을 다른 format으로 바꾸고 싶다면, utils.quat에 있는 to_xform(quaternion to 3*3 matrix), to_axis_angle(quaternion to axis angle form), ortho6ds(quaternion to 6d represetion) 함수를 사용하면 된다.
- proj_root_rot: root의 orientation을 땅에 projected 시킨 방향을 가리키는 orientation. 쉽게 말해 projected root centric(character local) 좌표 방향을 의미하는 값이라고 보면 된다. quaternion(w, x, y, z)로 표현되어 있다.
<4-2. Position value>
- lpos: parent joint에 대해 표현된 local position, 즉 root joint(pelvis)의 경우 global position, root가 아닌 joint의 경우 offset 값. (frame_num, joint_num, 3)의 shape를 가짐
- gpos: 모든 joint의 global position. (frame_num, joint_num, 3)의 shape를 가짐
- rtpos: root local한 좌표에 대해 표현된 모든 joint의 position. (frame_num, joint_num, 3)의 shape를 가짐
- cpos: projected root centric 좌표에 대해 표현된 모든 joint의 position, (frame_num, joint_num, 3)의 shape를 가진다.
- trans: root의 glboal position을 담고 있는 값. 즉 gpos 중 root에 해당하는 값만 가지고 있다고 보면 된다. (frame_num, 3)의 shape를 가진다.
<4-3. Velocity value>
- gposvel: 모든 joint의 global positional velocity
- cposvel: projected root centric 좌표계에 대해 표현된 joint의 position, (연속된 frame의 cpos 값을 가지고 계산)
- lrotvel: local rotation velocity, lrot 값을 사용해서 rotational vector style로 rotational velocity를 계산한거
<4-4. 4*4 Matrix value>
- local_transform: parent joint에 대해 표현된 transform. local_transform[:3, :3]은 xform 값과 동일하고 local_transform[:3, 3]은 offset과 동일하다. (주의: root(pelvis) joint의 transform의 경우 local_transform[:3, 3]이 root의 global position으로 setting되는게 바람직하지만, local_tranform[:3, 3]값은 root joint의 offset(bvh 파일에 세팅되는)을 가진다.)
- global_transform: root부터 해당 joint의 local_transform을 누적해서 곱해 만든 값인데, root의 lcoal_transform[:3, 3]이 이상하게 세팅되어 있다보니 global_trasnform의 값이 직관과 맞지 않음.
5. 생성된 animation 객체의 gpos(global position), rtpos(root local position), cpos(character local position), gposvel(global positional velocity) , trans 등 position과 관련된 성분이 cm 단위로 세팅되어있다.
굉장히 주의해야하는 부분 중 하나이다! bvh 파일과 smpl 파일의 trans 성분의 경우 보통 cm 단위로 표현이 되는데, 이런 파일을 로드하여 생성되는 animation 객체가 이 값을 그대로 사용하는지, cm 단위로 설정이 되어 있었다.
활용하기
1. character local coordinate 구하기
proj_root_rot = quat.to_xform(anim.proj_root_rot[frame_index])
proj_root_pos = anim.proj_root_pos[frame_index]
coordinate = np.identity(4)
coordinate[:3, 3] = proj_root_pos/100
coordinate[:3, :3] = proj_root_rot
2. character local position 구하기
character_local_position = anim.cpos[frame_index][joint_index]
3. character local velocity 구하기
character_local_velocity = anim.cposvel[frame_index][joint_index]
4. anim 객체 생성시 load_hand = False, load_hand = True의 차이점
load_hand = True로 주게 되면 애니메이션의 스켈레톤에 손의 골격이 포함되며, False로 주게 되면 애니메이션의 스켈레톤에 손의 골격이 포함되지 않고 left_hand, right_hand joint만 추가된다.
이때 left_hand, right_hand joint의 위치는 load_hand = True로 주었을 때 생기는 손의 골격 중 left_index1, right_index1이다. 즉, load_hand = False로 옵션을 주게 되면, load_hand = True로 주었을 때 생기는 손의 joint 중 left_index1과 left_index2가 left_hand, right_hand로 대체되고 나머지 손의 joint는 사라지게 된다.
'연구 > 컴퓨터 그래픽스' 카테고리의 다른 글
SMPL-X skeleton 뜯어보기 & SMPL-X to SMPL+H (0) | 2024.01.29 |
---|---|
Motion-X dataset 관련 내용 정리 (1) | 2023.12.27 |
6D Rotational representation 설명 및 구현 (0) | 2023.08.03 |
blender에서 한 model의 facial motion을 다른 model에 적용하기 (0) | 2023.06.26 |
angular velocity 구하는 방법 (0) | 2023.02.24 |