ㄷㄷㄷ

'대학생 졸업하기 전 레벨 > DirectX' 카테고리의 다른 글

물 렌더링 (쉐이더)  (0) 2009.03.15
쉐이더 에러시  (0) 2009.03.07
D3DX 조명  (0) 2007.12.03
Direct 3D 프로그래밍 과제  (0) 2007.11.12
픽킹. Projection 변환  (0) 2007.11.11
DirectX 3D 초기 소스  (0) 2007.10.08
일단 총알 쏘는 것까지 구현...
집에서한 회전축 돌리는것과 합쳐야 한다.. orz
이번주 까지가 총알 구현하고, 총알로 인한 충돌처리, 비행체는 박스 1에서만 맴돌다가
픽킹해서 다른지점 찍을때 글로 이동시켜야 함...

'대학생 졸업하기 전 레벨 > DirectX' 카테고리의 다른 글

쉐이더 에러시  (0) 2009.03.07
D3DX 조명  (0) 2007.12.03
Direct 3D 프로그래밍 과제  (0) 2007.11.12
픽킹. Projection 변환  (0) 2007.11.11
DirectX 3D 초기 소스  (0) 2007.10.08
DirectDraw의 기본 소스  (0) 2007.09.06
 http://blog.naver.com/gamed21/70018244989

픽킹. Projection 변환

중요하지 않은 부분들이 없겠지만.. 픽킹은 아주 중요한 부분이다.. 2D 에서의 마우스 처리는 아주 간단했다...

하지만 3D 에선 z 축이 포함되어 있기 때문에.. 단순히 마우스로 x. y 를 클릭하거나 움직였다면 어느 z 축선상인지 판별해야 한다..

x. y 좌표가 동일하고 z 축 좌표가 다른 물체중 어느 물체를 선택했는지 알수 있어야 한다.

즉. 스크린 좌표를 이용해 선택한 물체를 알아내는 테크닉을 "픽킹(picking)" 이라 한다..

또한 3D 공간 좌표를 2D 평면 좌표로 변환 하는 것을 "Projection(투영) 변환" 이라고 한다..

좀더 자세히 이야기를 하면 클리핑이 설정되어 있는 3D 공간좌표를 화면상의 좌표로 변환을 말한다...

관측점(눈) ---  Screen(화면) --- 가까운 클리핑 영역 ---  "물체" --- 먼 클리핑 영역

시야가 오른쪽으로 갈수록 커진다고 생각햐면 된다.. 지금 당장 책이나 이런것을 눈 가까이 갖다대면 눈에 책만 보이게 될것이다..

이것을 좀더 멀리 떨어트리면 책 이외에 주변 환경이 같이 보이고 책은 조그맣게 보일것이다.. 물체 역시 마찬가지이다.. 가까이 있으면 크게 보이고

다른 것이 안보이고.. 멀리 떨어트리면 조그맣게 보이고 그 주변에 것들이 같이 보인다..


SetupMatrices() 함수안에 D3DXMatrixPerspectiveFovLH() 함수가 있을것이다..


D3DXMATRIX matProj;

D3DXMatrixPerspectiveFovLH( 

              &matProj,               // 결과 생성 매트릭스

              D3DX_PI/4,               // 시야 범위

              1.0f,                       // 가로 해상도 / 세로 해상도 비율.  만약 가로 800 세로 600 이라면 1.333f 로 설정해야 제대로된 하면이 나온다.

              1.0f,                       // 가까운 클리핑 영역

              100.0f                     // 먼 클리핑 영역

);


가까운 클리핑 영역 보다 멀리 있고 먼 클리핑 영역 보다 가까운 영역에 있는 물체만이 출력이 된다.  보통 먼 클리핑 영역은 5000.0f 로 설정을 한다. (게임에서..)


시야 범위는 현재 D3DX_PI / 4 로 설정되어 있다. 이것은 45˚ 의 라디언값이 들어간다. 실제 사람의 시야 범위는 78˚ ~ 113˚ 정도라고 한다.

시야가 넓어질수록 많은 것이 보이겠지만 볼록하게 왜곡현상이 보이게 된다..  화면 비율은 보통 4 : 3 비율로 설정을 해놓은다..













A : Screen

B : 가까운 클리핑 영역

C : 먼 클리핑 영역


현재 Y의 좌표가 0 이라고 하고 위에서 봤을때 X 축이 0 보다 오른쪽에 있고 Z 축 선상에 있는 점을 X3. Z3 라고 하고 이 좌표를 구하면 된다..

이그림을 다시 반으로 나눠서 살펴보면...

















a * k(비례상수)  =  X3

b * k(비례상수)  =  X2    단. 0.0f <= k < 1.0f


         X3

a  =   ───

          k


식을 도출해하면...  (단 Z3 = 1.0f 일때.. )


a : b  =  Z3 : d

X3

── : b  =  Z3 : d     ( 닮은꼴 )

 k

             X3 * d

b * Z3 =  ────     ( 등가연산 )

                 k

       X3 * d      X3 * d      X3

k  =  ────  =  ────  =  ──  * Proj( 1. 1 )

       b * Z3      Z3 * d      Z3

                                Width            Width      X3

X2  =  b * k(비례상수)  =  ──── * k  =  ──── * ─── * Proj( 1. 1 )

                                   2                 2          Z3

                          X3                     Width   Width

화면 보정 좌표 X2  =  ── * Proj( 1. 1 ) * ─── + ───            ( 실제 화면 보정 )

                          Z3                        2        2


정리


 X2 * 2        X3

─────  =  ── * Proj( 1. 1 ) + 1

 Width         Z3


          X2 * 2

          ────  -  1

 X3      Width 

──  =  ───────

 Z3      Proj( 1. 1 )


         X2 * 2

        ────  -  1

         Width

X3  = ───────

         Proj( 1. 1 )


Y3 도 같은 원리로 했다면...


         Y2 * 2

        ─────  -  1

         Height 

Y3  = ───────

         Proj( 2. 2 )               단. Z3 = 1.0f 일때..



먼저 좌표를 구하기 전에 카메라를 이용하여 DX 에서 어떤식으로 계산을 하는지 잠깐 살펴보자..

카메라의 입장에서 원점에서 카메라에 설정된 값으로 선을 그려보면 아래와 같은 형태가 될것이다.





















z 선상이 안보이면 된다. 정면에서 바라보고 있으니...


D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 3.0f,-5.0f ),       // eye
                                            &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),        // look
                                            &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );      // up


위에 있는 세개의 좌표를 위해 원점부터 각 좌표 까지 선을 그리면 된다.. ex) 원점(0.0f. 0.0f. 0.0f)  ~ Eye(0.0f. 3.0f. -5.0f )

g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); 로 설정을 해주니..


1. 원점 ~ matView._11. matView._12. matView._13    // 빨간색

2. 원점 ~ matView._21. matView._22. matView._23    // 녹색

3. 원점 ~ matView._31. matView._32. matView._33    // 파란색


하지만 결과를 본다면...






















이런 결과가 나오게 된다. 뭔가 틀린것을 느낄수 있을것이다.


1. 원점 ~ matView._11. matView._21. matView._31    // 빨간색

2. 원점 ~ matView._12. matView._22. matView._32    // 녹색

3. 원점 ~ matView._13. matView._23. matView._33    // 파란색


이런식으로 값을 줬다면...






















이런 결과를 얻을수가 있다...


* DX 계산


 Rx    Ux    Vx    0    

 Ry    Uy    Vy    0    

 Rz    Uz    Vz    0    

-P.R -P.U  -P.V   0      // 카메라의 위치


의 형태로 되어 있기 때문이다... 만약 matView 를 역행렬 한다면..


D3DXMATRIX matInv;
D3DXMatrixInverse(&matInv, NULL, &matView);
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );


1. 원점 ~ matInv._11. matInv._12. matInv._13    // 빨간색

2. 원점 ~ matInv._21. matInv._22. matInv._23    // 녹색

3. 원점 ~ matInv._31. matInv._32. matInv._33    // 파란색


이렇게 너주면 된다...


-P.R -P.U  -P.V  


→  →

P   R

각 성분끼리의 곱의 합을 내적이라고 한다. ( 벡터와 벡터가 만났을때..)


ex )

→  →

a   b     =  ( ax * bx ) + ( ay * by )    3D 에서는 z 가 추가 된다..


사실 내적은 벡터 대수학에서 정의하는 두가지 곱셈 중 하나이며 이는 그래프적으로 눈에 보이는 개념이 아니다.


* 계산 : u·v =  uxvx + uyvy + uzvz  = s

코사인 법칙을 이용하면 u·v = ||u|||||v|| 의 관계를 가지며 이는 두 벡터 간의 내적이 벡터 크기 비율을 가진 벡터 간 각도의 코사인 임을 알수 있다.


* 내적의 특징

1. 만약  u·v = 0  이라면 u⊥v 이다.   (  ⊥ = "직각" 을 의미하며 "수직" 과 같은 의미이다. )

2. 만약  u·v > 0  이라면 두 벡터 간의 각도 ∂ 는 90도 보다 작다.

3. 만약  u·v < 0  이라면 두 벡터 간의 각도 ∂ 는 90도 보다 크다.


            →     →

cos∂ *   |a| * |b|     ( | | 절대값표시.. )

            _________         _________

cos∂ * √ ax + ay²    +  √ bx² + by²            


             →         →

             a          b

cos∂  =  ──    *  ──

             →         →

            |a|        |b|


acosf(Radian) 이용..




[ 픽킹 ]


3D 좌표 공간에 있는 삼각형에 마우스를 갖다대면 WIRE 모드로 변환되게 구현..


// 삼각형...

CUSTOMVERTEX g_Vertices[] =
{
     { -1.0f,-1.0f, 0.0f, 0xffff0000, },
     {  1.0f,-1.0f, 0.0f, 0xffff0000, },
     {  0.0f, 1.0f, 0.0f, 0xffff0000, },
};

..............................


// 체크

BOOL IntersectTriangle( const D3DXVECTOR3& orig,
        const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
        D3DXVECTOR3& v1, D3DXVECTOR3& v2,
        FLOAT* t, FLOAT* u, FLOAT* v )
{
     D3DXVECTOR3 edge1 = v1 - v0;
     D3DXVECTOR3 edge2 = v2 - v0;


     // Begin calculating determinant - also used to calculate U parameter
     D3DXVECTOR3 pvec;
     D3DXVec3Cross( &pvec, &dir, &edge2 );


    // If determinant is near zero, ray lies in plane of triangle
     FLOAT det = D3DXVec3Dot( &edge1, &pvec );
     if( det < 0.0001f )
        return FALSE;


     // Calculate distance from vert0 to ray origin
     D3DXVECTOR3 tvec = orig - v0;


     // Calculate U parameter and test bounds
     *u = D3DXVec3Dot( &tvec, &pvec );
     if( *u < 0.0f || *u > det )
        return FALSE;


    // Prepare to test V parameter
     D3DXVECTOR3 qvec;
     D3DXVec3Cross( &qvec, &tvec, &edge1 );


    // Calculate V parameter and test bounds
     *v = D3DXVec3Dot( &dir, &qvec );
     if( *v < 0.0f || *u + *v > det )
        return FALSE;


     // Calculate t, scale parameters, ray intersects triangle
     *t = D3DXVec3Dot( &edge2, &qvec );
     FLOAT fInvDet = 1.0f / det;
     *t *= fInvDet;
     *u *= fInvDet;
     *v *= fInvDet;

     return TRUE;
}


VOID SetupMatrices()
{

     // eye 와 Look 은 알아서.. 회전을 하게 나둬도 되고 값을 줘도 된다...
     D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( eyex, eyey, eyez),
                                                 &D3DXVECTOR3( lookx, looky, lookz ),
                                                 &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
   

     // 역행렬
     D3DXMATRIX matInv;
     D3DXMatrixInverse(&matInv, NULL, &matView);
     g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
 
     D3DXMATRIX matProj;
     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.33f, 1.0f, 100.0f );
     g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}


VOID Render()
{

     g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
     g_pd3dDevice->BeginScene();
   

     SetupMatrices();


     D3DXMATRIX matProj;
     D3DXVECTOR3 vPickRayDir;
     D3DXVECTOR3 vPickRayOrig;

     g_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );


     // 스크린 계산..   마우스 좌표변수 mousex . mousey    

     D3DXVECTOR3 v;
     v.x =  ( ( ( 2.0f * mousex ) / WIDTH_RES  ) - 1 ) / matProj._11;   // WIDTH_RES : 가로 해상도
     v.y = -( ( ( 2.0f * mousey ) / HEIGHT_RES ) - 1 ) / matProj._22;  // HEIGHT_RES : 세로 해상도
     v.z =  1.0f;


     // 매트릭스를 가져온다. Get

     D3DXMATRIX m;
     g_pd3dDevice->GetTransform( D3DTS_VIEW, &matView );           // SetTransform 에 있는것을 가져오는 역활
     D3DXMatrixInverse( &m, NULL, &matView );


     // 3 x 3 행렬과 벡터와의 곱

     // ORIG : CAMERA POSITION

     // Transform the screen space pick ray into 3D space

     vPickRayDir.x  = v.x*m._11 + v.y*m._21 + v.z*m._31;
     vPickRayDir.y  = v.x*m._12 + v.y*m._22 + v.z*m._32;
     vPickRayDir.z  = v.x*m._13 + v.y*m._23 + v.z*m._33;
     vPickRayOrig.x = m._41;
     vPickRayOrig.y = m._42;
     vPickRayOrig.z = m._43;


     // 삼각형 좌표

     D3DXVECTOR3 v0, v1, v2;
     v0.x = -1.0f, v0.y = -1.0f, v0.z = 0.0f;
     v1.x =  1.0f, v1.y = -1.0f, v1.z = 0.0f;
     v2.x =  0.0f, v2.y =   1.0f, v2.z = 0.0f;


     // 체크를 해서 마우스좌표가 삼각형 안에 있을때 WIREFRAME 모드. 아닐땐 SOLID 모드..

     if( IntersectTriangle( vPickRayOrig, vPickRayDir, v0,v1, v2,
                                 &m_fPickT, &m_fPickU, &m_fPickV ) )
     { g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME); }
     else
     { g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID);  }


    // 삼각형 출력

     g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
     g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
     g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );


     g_pd3dDevice->EndScene();
     g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

 

간단한 픽킹 예제이다.. 오브젝트 처리와 이런것들은 좀더 공부를 해야 한다...

'대학생 졸업하기 전 레벨 > DirectX' 카테고리의 다른 글

D3DX 조명  (0) 2007.12.03
Direct 3D 프로그래밍 과제  (0) 2007.11.12
픽킹. Projection 변환  (0) 2007.11.11
DirectX 3D 초기 소스  (0) 2007.10.08
DirectDraw의 기본 소스  (0) 2007.09.06
역전재판 소스.... 자작  (0) 2007.09.06
이건 붉은 용책의 기본 소스임.
컴파일전
d3d9.lib d3dx9.lib winmm.lib 를 포함시켜야 하는건 당연한 상식
cube 를 만들어서 회전하는 프로그램이지만
cube의 begin, cleanup, display 함수만 깨끗히 지우면 완전 초기화 상태임

'대학생 졸업하기 전 레벨 > DirectX' 카테고리의 다른 글

D3DX 조명  (0) 2007.12.03
Direct 3D 프로그래밍 과제  (0) 2007.11.12
픽킹. Projection 변환  (0) 2007.11.11
DirectX 3D 초기 소스  (0) 2007.10.08
DirectDraw의 기본 소스  (0) 2007.09.06
역전재판 소스.... 자작  (0) 2007.09.06

+ Recent posts