티스토리 뷰

Kinect

[Kinect with XNA] Minority Report Navigation

생각많은 소심남 2012. 12. 10. 00:57

이번 포스트에서는 XNA상에서 개체를 Grab하고 Release 하는 것을 구현해보고자 합니다. 원본에서는 이걸 Minority Report Navigation이라고 하더군요. 

대충 구현 해볼 것은 오른손으로 특정 개체에 닿으면 손의 움직임에 따라서 개체가 움직입니다. 그 상태에서 박수를 치면 다시 원래 자리로 돌아가는 형태를 취하게끔 할겁니다.


일단 XNA 프로젝트로 하나 생성하고 키넥트를 쓰기위한 dll 파일과 네임스페이스를 추가해줍니다. 그 후에 키넥트를 활용하기 위해서 키넥트자료형을 하나 생성합니다.



그리고 창 크기를 먼저 지정해줍니다. 저는 640x480의 창에서 동작시킬 예정입니다.



그리고 Initialize()에서 자신이 활용할 키넥트 기능을 활성화시킵니다. 당연한 것이겠지만 오른손을 추적하려면 Skeletal Tracking이 필요하겠고, 그냥 실제 모습을 보여주기 위해 ColorStream을 뽑아내도록 합시다. 그럼 그 부분은 다음과 같이 채워지게 됩니다.



일단 Color부터 뽑아냅시다. 그러면 AllFrameReady에서 ColorStream을 뽑기 위한 코드를 삽입해줘야 하겠지요. 



일단 colorStream으로부터 Frame을 뽑아와야 하는데 바로 뽑아올 수 있는게 아니라 특정 배열에서 복사한 후에 전달하는 과정을 거치게 됩니다. 그때문에 사전에 byte형 배열을 만들어서 이용하고자 합니다.



그리고 나서 위처럼 크기를 지정해준 후에 복사를 하게 됩니다. 그런데 이 정보를 보기 위해서는 뭔가 시각적인 이미지로 바꿔줘야 하는데 WPF 상에서는 BitmapImage라는 컨트롤이 있기에 이미지를 표현하기가 쉽습니다만 XNA에서는 말 그대로 하나하나 그리는 과정을 거쳐야 합니다. 물론 색상도 하나하나씩 다 넣어줘야 하고요. 그대신 그리는 과정은 뒤에 나오는 Draw에서 이뤄지고 여기서는 색상을 선택해주면 됩니다. 그러기 위해서는 그리기 위한 판을 하나 Texture2D로 선언해줘야 합니다.



그리고 나서 아까 만든 ColorFrame 생성과정에서 크기를 지정해줘야 하겠지요.



그다음  Color를 만들어주면 됩니다.



다른 포스트에서도 이야기했었지만 colorPixel은 rgbX,rgbX,....의 형식으로 저장이 되기 때문에 Color에 집어넣을 때도 이를 유의하면서 넣어줘야 합니다. 아니면 정말 이상한 색이 Color로 뿌려지게 되는 것이죠. 

자 이제 Color를 화면에 출력시키려면 Draw에서 딱 이렇게만 넣어주면 됩니다.



조건문을 통해서 Texture가 있을때만 화면상에 그려지게끔 했습니다. 이렇게 하고 실행시키면 다음과 같이 나옵니다.



자 이제 화면상에 아이콘들을 배치해야겠지요. 다음 3개의 이미지를 배치해보도록 하겠습니다.





여러분들이 이 이미지를 쓰실거면 아래의 압축 파일을 받으셔서 프로젝트에 추가시켜주시면 됩니다.


minority ReportContent.zip

보다시피 크기가 각각 다릅니다만 이것을 입힐 Texture2D의 크기를 똑같게 하면 동일하게 바뀌겠지요.

자 추가시킨 상태에서 Texture2D 자료형을 선언해줍니다. 그리고 이걸 그릴 Rectangle도 하나 추가시켜주는게 좋겠지요.



이제 추가시켜준 이미지를 이 자료형에 넣어줘야 하겠지요. 이건 LoadContent에서 이뤄집니다.



자 Draw에서 이걸 그대로 대입해주면 됩니다. 그리고 Rectangle에 대한 설정을 Update에서 바꿔주게 되면 우리가 원하는 기능을 구현할 수 있게 되지요. 



자 이제는 Skeleton을 잡아보도록 하겠습니다. 우리가 필요한건 오른손과 왼손(왼손은 박수칠때) 겠지요. 일단 필요한 변수를 선언해주고 하는김에 사각형의 위치도 정해주도록 하겠습니다.




자 이제는 Skeletal Tracking이 되야 하는데 앞에서 미리 담아놓을 배열을 선언해놓습니다.



그리고 위와 비슷하게 배열을 만들고 복사하는 과정을 거칩니다.



그리고 SkeletonData중에 추적되는 오른손과 왼손 좌표만 잡아서 앞에서 선언한 변수에 집어넣습니다. 그런데 이렇게 뽑은 좌표는 3차원 좌표이므로 이걸 ColorStream 상에 픽셀 좌표로 변환시켜줘야 겠지요. 이때 쓰는게 CoordinateMapper입니다. 그래서 다음과 같이 작성해줍니다.



이렇게 하면 이제 오른손과 왼손의 좌표가 ColorStream상의 pixel 좌표로 뜨게 됩니다. 

이제 충돌 이벤트를 만들어야 됩니다. 이때는 몇번 나왔던 내용이지만 flag라는게 필요하고 보통은 이걸 bool형으로 선언해줍니다.


그리고 이제 update에서 프로그램 로직을 짜야 합니다. 그런데 간단하겠지요. 충돌하면 아까의 Texture의 좌표가 손 좌표가 되고 박수치면 원래로 돌아가게 하는 겁니다. 그렇게 하기 위해서는 지금 표현되어 있는 개체들이 모두 Rectangle로 표현되어야 합니다. 그러고 보니까 오른손과 왼손에 대한 Rectangle도 필요하겠네요.



이제 Update()인데 먼저 위치를 사전에 지정해주는게 좋겠지요.




자 이제 충돌이벤트를 만들어야 되는데요.저번에 잠깐 설명드렸다시피 Rectangle에는 속성함수로 Intersects라는게 있습니다. 이걸 활용하면 됩니다.



이중 맨 마지막에 대한 조건은 박수를 쳤을때에 대한 조건인데 당연히 오른손과 왼손이 충돌했을때 모든 플래그를 해제시키면 되는거겠지요. 이건 단지 플래그만 설정한 것이므로 이제 하단부에 플래그에 따른 위치를 조절하게 해주면 됩니다.



실행시키면 다음과 같이 나옵니다.



이 상태에서 건드리면 손위치에 따라서 위의 아이템들이 움직일 것이고 박수를 치면 원래대로 돌아가겠지요. 결과는 다음과 같습니다.



지금까지 충돌 이벤트와 플래그를 통해서 하나의 박수 제스쳐를 구현해봤습니다. 물론 복잡하게 제스처를 구현할 수도 있겠지만 이런식으로 구현하면 다른 분들도 쉽게 구현할 수 있을거라고 생각합니다.


댓글