'피킹'에 해당되는 글 1건

  1. 2016.08.29 DirectX9 픽킹 개념.
프로그래밍/DIrectx92016. 8. 29. 02:21

-3D Game프로그래밍 입문의 내용중 핵심만 정리해봤습니다.


예를들어 위와 같은 3D공간이 있고. 스크린s지점을 클릭했을때. 우리는 사용자가 주전자를 선택했음을 즉시 알수 있지만. 컴퓨터 입장에서는

s만 가지고 곧바로 주전자가 선택되었는지를 알수는 없다. 왜냐하면 클릭한지점 S는 스크린 상의 좌표이지(2D상의), 3D공간상의 좌표와는 다르기 때문이다. 

스크린좌표를 이용해 선택한 물체를 알아내는 기술이 필요한데. 이와같은 기술을 픽킹이라고 한다.




우리가 3d 물체와 클릭한 스크린 포인트 x,y의 관계에 대해서 알고있는것은 아래와 같이 3d 물체가 포인트 영역 주위에 투영되어 있다는 것이다.

이를통해 투영의 중심(여기서는 카메라위치) 로부터 p를 통과하도록 광선을 발사하고 그것이 물체과 교차하는지를 확인하면 사물과의 관계에 대해서 알수 있게 된다.

 다이렉트에는 이러한 픽킹 광선을 만들어내고, 특정 면이나 메쉬와 교차하는지를 구할 수 있는함수가 있는데, 

 D3DXIntersectTri()함수와 D3DXIntersect()함수 이다.


이 함수들을 통해 광선을 만들기 위해서는 광선의 발사위치,광선의 방향을 구해야 한다. 

광선의 발사 위치와, 방향을 구했다면 이것들로 광선을 발사해서 광선이 물체의 면에 부딛히는지 확인하면 된다.



이함수들를 사용하기 위한 인자들 중에 구해야 하는 것들로는 광선의 발사위치와 발사방향,광선과 부딛힐 면의 버텍스가 정도가있다.

면의 버텍스는 충돌을 확인할 물체의 버텍스를 넣어주면 되고,

 발사위치와 방향을 구해야 되는데

여기서는 발사위치를 카메라 위치로 할것이므로, 방향만 구하면 된다.


방향을 구하는 방법은 아래와 같다.


첫번째로 해야 하는 것은. 스크린 포인트를 투영창으로 변환하는 것이다.

원래 투영창의 포인트 p=(px,py,pz)에 뷰포트 변환을 거치면 우리가 알고있는  화면상의 좌표S = (sx,,sy)가 나온다.

이를 활용하면 스크린 포인트를 이용해 역으로 투영창의 포인트를 구할수 있을 것이다.

하지만 한가지가 더 필요한데. 투영행렬은 투영창의 포인트 배율을 변경하기 때문에 배율이 변경되기 이전의 원래 포인트 값을 얻으려면

배율 연산의 열을 통해 포인트를 변환해야 한다고 한다.

투영행렬이 P일때 변환 행렬의 P_00 값과 P_11항목이 포인트 x,y좌표의 배율을 변경한다고 한다.

이를 이용하면 다음과 같은 공식 얻을수 있다고 한다.


여기서 구한 Px,Py,Pz가 투영창의 포인트 이다.

// 뷰포트 행렬의 과, 투영행렬을 구하기 위해서는 directx에서 제공해주는 함수를 사용하면 된다.

D3DVIEWPORT9 vp;  //뷰포트의 정보를 담아둘 구조체

디바이스->GetViewport(&vp);  //vp에 뷰포트의 정보가 넘어간다.

D3DXMATRIX ProjectionMat;  //투영행렬을 저장할 매트릭스변수

디바이스->GetTransform(D3DTS_PROJECTION, &ProjectionMat); //투영행렬을 받아온다.

이를 통해 얻어온 값을 위의 공식에 대입하면 된다. (공식에서의 x,y는 화면상의 좌표)


광선의 원점은 임의로 설정할수 있지만 여기서는 첫번째 그림과 같이 카메라의 시작지점을 원점으로 할 것이다.

따라서 광선의 원점은 0,0,0,이고 원점과 포인트를 알고 있으니까 원점으로부터 해당 포인트까지의 방향 벡터를 구할수 있다(포인트벡터-원점벡터)

이제 원점과 방향벡터를 알고있으니 광선을 발사할 수 있게 됬다.


이제 광선과 사물을 같은 스페이스 상으로 놓고 광선과 사물이 닿는지 검사를 하면 된다.

우리가 위에서 구한좌표는 뷰스페이스상의 좌표이다.

따라서 사물을뷰스페이스로 변환하거나  아니면 구한 광선을 월드스페이스나 로컬스페이스로 변환한 후에

D3DXIntersectTri()함수와 D3DXIntersect()함수를 통해 면과 광선이 충돌하는지에 대한 정보를 알아낼수 있게 된다.

위의 함수를 사용하는 방법 말고도 사물을 둘러싸고 있는 구를 만들어서 구의 원점과 반지름과, 구한 좌표상의 관계를 통해 확인할 수도 있다.



밑에는 제가 숙제로 만들어본 영상입니다.

좌클릭으로 케릭터 선택(선택된 케릭처만 택스쳐를 씌움) //케릭를 둘러싸고 있는 구가 있습니다. 구와 광선을 충돌처리 했습니다.

캐릭터를 선택한 상태로 바닥을 우클릭 하면 해당 지점으로 이동. //바닥과 광선과 충돌처리 후 출돌지점 좌표를 구해서 그 방향으로 이동.

케릭터를 이동지점방향으로 회전시켜주고 이동할때는 달리는 애니메이션이 나옴.







Posted by JinFluenza