통신을 시작하기 전 mediaPipe 모듈을 실행해보았다. 웹캠(webcam)을 키고 몇 초간 어떤 동작을 수행하면서, 필요한 13개의 관절 위치값을 텍스트 파일에 기록했다.

이 텍스트 파일의 값들을 아바타에 적용시켜서 아바타가 동작을 잘 수행하는지 최종적으로 점검 했다.
아바타 관절을 움직이는 코드는 저번 게시물 참고🙂
저번 게시물
저번 게시물에서 텍스트 파일에 기록되어있는 관절값을 가져와 아바타에 적용한 후 아바타가 잘 움직이는 것을 확인했다.
그런데, mediaPipe 모듈로 측정한 데이터를 아바타에 적용했을 때 아바타의 동작이 잘 수행되지 않고, 아바타의 몸도 이상해졌다(보기 흉함..)
mediaPipe의 Pose Landmark model은 두가지의 Output을 리턴한다.
Output 하나는 Landmarks 이고, 다른 하나는 WorldLandmarks 이다.
나는 WorldLandmarks 결과를 사용해 관절의 위치를 텍스트 파일에 기록했다.

WorldLandmarks는 관절의 x, y, z값이 모두 엉덩이 사이의 중심(24번과 23번의 중심값)을 원점으로 하는 상대좌표이다.

따라서 mediaPipe 모듈로 측정한 관절의 좌표값을 이용해 아바타를 움직이기 위해선 코드의 수정이 필요하다.
다른 클래스의 코드는 그대로 두고 StoreJointData.cs의 MakeVirtualData 함수를 수정한다.
// 가상의 관절 만들기, 관절 위치 재조정
public void MakeVirtualData()
{
// 가상의 목 관절의 위치 구하기
virtualNeck = (trackJoint[1] + trackJoint[2]) / 2.0f;
virtualNeck.y += 0.05f;
// 가상의 힙 관절의 위치 구하기
virtualHips = (trackJoint[7] + trackJoint[8]) / 2.0f;
virtualHips.y += 0.95f;
//가상의 UpperChest 관절 위치 구하기
virtualUpperChest = (trackJoint[1] + trackJoint[2]) / 2.0f;
virtualUpperChest.y -= 0.1f;
virtualNeck += virtualHips;
virtualUpperChest += virtualHips;
for (int i = 0; i < 13; i++)
{
trackJoint[i].y *= -1f; // 트래킹한 조인트 값의 y좌표가 땅과 반대로 되어있음
trackJoint[i] += virtualHips; // pose_world_landmarks는 엉덩이 중간 포인트를 기준으로 상대좌표이므로 Hips의 위치를 더해 절대 좌표를 구해준다.
}
anim.GetBoneTransform(HumanBodyBones.Hips).position = virtualHips;
}
virtualHips(엉덩이 사이의 중간 지점)의 위치는 절대 좌표로 잡아두고, 다른 관절들은 virtualHips 위치를 더해 3차원 절대 좌표로 바꾸어준다.
mediaPipe의 모델이 사용하는 3차원 좌표계와 유니티에서 사용하는 좌표계의 차이가 있어 y좌표값이 반대로 되어 있음을 발견했다.
trackJoint[i].y *= -1f;
트래킹한 관절의 y좌표 값에 -1을 곱해 방향을 바꾸어 아바타의 몸이 반대로 뒤집어 지지 않도록 코드를 수정한다.
코드를 수정한 후 다시 데이터를 적용했을 때 아바타가 잘 움직인다😁
이제 노트북 웹캠을 통해 실시간 관절 데이터를 유니티 서버로 전달하고, 실시간으로 아바타를 움직여 볼 것이다.