목적
피사체의 위치와 피사체가 바라보는 방향을 실시간으로 계산하는 헤드트래킹을 구현하기로 함, 이를 위해 Wiimote 두개와 IRED 3개로 구성된 표식자(태그)를 사용하였습니다.
특징
일반적으로 알려진 헤드트래킹은 피사체의 2차원 or 3차원 공간 좌표값(x,y,z) 성분만을 계산할 수 있는 제한이 있습니다.
본 3광점 태그를 이용한 헤드트래킹은 피사체의 위치와 더불어 방향벡터(로컬좌표계)까지 완전하게 계산하낼 수 있으므로 좀더 다양하게 응용할 수 있습니다.
용도
헤드 트래킹의 용도는 광범위하나 여기서는 3D 스캐닝 작업시, 여러차례 나눠서 스캐닝하지 않고, 한번에 피사체의 전체를 스캐닝하는데 활용하는 것을 가정하였습니다.
결과
헤드트래킹은 구현완료 하였으나 3D 스캐너 관련 개발은 현재 보류된 상태입니다. (
3D 스캐너 관련글 링크)
One Step Full Scanning 구현은 언제가 될지 모르지만 꼭 완성하고 싶네요, 여러분이 먼저 하시렵니까??;;
방법 소개
3광점 표식자
헤드트래킹을 구현하기위해선 피사체에 고정되어 있는 정점(Vertex) 좌표값이 적어도 3개가 필요합니다. 물론 단순히 피사체의 위치벡터만 구하는 경우라면 두개의 Wiimote로 한개의 정점 좌표값만 구해도 됩니다만 이경우 정점의 3차원 좌표(x,y,z)값만을 알 수 있고 피사체의 2축 회전성분을 알수가 없으며, 정점 좌표가 2개인 경우엔 위치파악 및 2축 중 1축 회전성분을 알수 있습니다. 결국 피사체에 고정되어 있는 3개의 정점을 알아야 완전한 위치와 방향 성분을 갖는 벡터값을 구해낼 수 있습니다.
Wiimote
위모트는 한번에 4개까지의 IRED(적외선LED)광점을 인식할 수 있는 기능이 있습니다. 특정파장(940nm)의 적외선에 반응하므로 너무 밝지 않은 실내라면 별도의 장비없이도 쓸만한 광점인식 장비로 사용할 수 있습니다. 피사체에 3개의 IRED를 고정시킨 후 실시간으로 두개의 Wiimote로 그 광점들의 좌표값을 측정하는것으로 피사체의 위치와 바라보는 방향을 구할 수 있게됩니다.
3개의 정점으로 정의되는 Local 좌표계 구하기
위모트를 사용해보신 분들이라면 광점 3개를 읽어들이는것은 어렵지 않게 할 수 있습니다만, 실제 이값을 가지고 피사체의 벡터(위치와 방향)성분을 구해내는건 약간의 벡터연산에 대한 이해가 필요합니다. 사실 고등학교때부터 배워온 벡터지만,, 막상 써먹으려니 막막하더군요, 어쨌든 간만에 벡터연산 공부좀 하고 해답을 구했습니다. 정리해놓고 보면 별거 아니네요.
이제 순서대로 정리를 해보도록 하겠습니다.
1단계. 3광점의 3차원 좌표값 구하기
Wiimote 2개로 광점 3개의 2차원 좌표값들을 구하고 이값으로 3차원 좌표값 P1, P2, P3을 구해놓습니다. 이와 관련된 내용은
3D 포인트 트래킹 구현하기 글에 소개되어 있습니다. 이값은 웹캠이나 기타 다른 방식으로 구할 수 도 있습니다.
준비된 결과 값:
P1(x,y,z) P2(x,y,z) P3(x,y,z)
2단계. 문제정의
3개의 정점으로 구성된 Local 좌표계 구하기라고 목표를 정의했지만, 사실 애매한 표현입니다. 수학적으로 엄밀한 표현까지는 아니더라도 좀더 구체적인 정의가 필요합니다. 그림으로 표현하는게 가장 이해하기 쉬울듯 합니다. 정의 방법에 따라 무수히 다른 방식의 좌표계 정의를 내릴 수 있을텐데요, 여기선 단계적으로 손쉽게 이해하고 계산하기 쉬운 방식으로 정의하겠습니다.
그림. 로컬 좌표계와 P1,P2,P3 관계 정의도
3단계. 계산하기
우리가 구해야할 값은 위 그림에서 u1,u2,u3로 표현된 벡터값 입니다. 각각 Local좌표계의 x,y,z축에 해당하는 벡터입니다. 헤드 트래킹의 경우, 월드좌표계안에서 헤드의 위치와 방향을 바로 이 좌표계 정보로 표현 한다는 개념입니다.
아래의 수식은 실제로 Away3D라는 플래시 3D엔진에서 Number3D 자료형의 벡터연산 메소드(함수)를 이용하여 계산하는 예입니다. 벡터 빼기 연산은 sub() 로, 벡터 외적 연산은 cross() 로 표기됩니다.
P1->P2 를 벡터A 로 정의합니다.
P1->P3 을 벡터B 로 정의합니다.
A.sub( P1 , P2);
B.sub( P1 , P3);
이제 위 정보로 u1,u2,u3를 구합니다. 이때 방향성분이 중요하고 크기(길이)는 중요치 않습니다.
(참고로 위 그림에서 u벡터들의 길이는 실제값이 아니고 임의의 크기로 표현했음에 주의바랍니다.)
여기선, 두 벡터를 외적(Cross Prduct)하면 서로 직교하는 제 3의 벡터를 구할 수 있다는 것을 응용합니다.
첫번째 로컬 좌표축 성분 벡터인 u1은 A와 B의 벡터 합으로 정의하고
두번째 로컬 좌표축 성분 벡터인 u2는 A와 B의 외적으로 정합니다.
세번째 로컬 좌표축 성분 벡터인 u3는 u1과 u2의 외적으로 구합니다.
u1.add( A, B);
u2.cross( A, B);
u3.cross( u2,u1);
위 연산으로 벌써 결과가 구해졌습니다. 벡터연산 함수를 사용하면 뺄셈 2번, 덧셈 1번, 곱셈2번으로 끝나는 매우 간단한 연산입니다. 이렇게 구한 벡터 3개는 모두 나머지 두 벡터와 직교하는 벡터가 되며, 로컬좌표계의 3개의 축 정보로 사용할 수 있습니다. 보통 좌표계의 축벡터는 크기가 중요하지 않으므로, 아래와 같이 크기가 1인 단위벡터로 변환하는 연산(Normalize)을 해줍니다. 위 그림에서는 u1,u2,u3 벡터를 단위길이 벡터로 변환한 것이 ^u1, ^u2, ^u3 로 표현되었습니다.
u1.normalize();
u2.normalize();
u3.normalize();
결과값과 활용
여기서 구한 u1,u2,u3를 이용하여 로컬좌표계를 정의할 수 있고, 월드좌표계와 좌표계변환 연산등을 할 수 있습니다. 좌표계 변환은 행렬연산과 관련된 또다른 주제가 됩니다. 그 부분은 기회가 되면 Away3D같은 3D 엔진 예제와 함께 설명 드릴 예정입니다. 계획했던 연관 프로젝트 진행이 중단되어 아직 보여드릴 만한 응용예제가 없네요, 추후 예제가 생기면 추가하겠습니다. 아래의 이미지는 실제 헤드트래킹 과정을 기록해둔 동영상의 한장면을 캡쳐한 것입니다. 머리의 움직임에따라 우측에 보이는 화면속 삼각형(+로컬좌표축)의 위치와 방향이 변합니다.
우측 부분에 월드 좌표축과 삼각형 위에 붙은 작은 좌표축(헤드의 로컬좌표축)이 희미하게나마 보입니다.
끝으로
헤드트래킹을 구현한지가 벌써 반년이 넘어버렸습니다. 그동안 정리는 뒤로 미루고 새로운 일을 벌리곤 했지만 지나보니 정리를 안해놓으니 남는게 없네요;; 앞으로라도 좀더 정리된 자료를 만드는 습관을 들여서 개인 프로젝트 히스토리 관리도 하고 약간이나마 공공지식에의 공언도 해야겠다는 생각이 듭니다. 그러나,,,오랜만에 그림 하나 그리는데 왜이리 힘든지요 ^^;;
관련링크
1. 외적(Cross Product)연산 :
wikipedia
2.
1광점 트래킹하기 (3차원 좌표값 실시간추적)