Tutorial3_Matrices 기초


3D 그래픽에서는 행렬은 필수요소다.
D3D를 사용할 때는 반드시 "월드, 뷰, 프로젝션"의 행렬값을 설정해주어야만 한다.

 

* 월드(월드좌표)

3D에서 기본적으로는 모든 정점은 로컬 좌표계(혹은 모델 좌표계)값을 갖는다. 이 값들은 최초에 3차원 데이터가 생성되는 시점에서 기준이 되는 원점을 중심으로 한 좌표계이다. 하지만 이러한 것의 문제는 동일한 공간에 여러 개의 물체를 띄우고자 할 때 발생한다. 모든 물체들이 각각의 고유한 원점을 기준으로 모델링되어 있기 때문에 여러 개의 물체를 3차원 공간에 띄울 경우 이들 물체들이 모두 원점을 공유하게 되는 현상이 발생하는 것이다. (즉, 중앙 원점에 겹친다는 것이다.)

 

이런것 문제를 해결하기 위해서 각각의 로컬 좌표계를 월드기준의 좌표계로 변환시켜 주어야 한다. 이러한 변환을 위해서 행렬을 사용하므로 Transform Matrix(변환 행렬)라고 하며 줄여 TM이라고 부른다. 즉, 각각의 로컬 좌표계를 갖고 있는 3차원 물체를 월드 좌표로 바꿔주어 서로 다른 위치하게끔 해주는 것이다.
TM은 물체마다 고유하게 하나씩 존재함.

 
 

* 뷰(뷰좌표,카메라좌표)

3D 월드에 물체를 띄웠으면 이제 그것을 보기위한 카메라를 설치해야 한다. 이를 카메라 변환(Camera Transform)이라 하며 3차원 월드 좌표계를 카메라를 기준으로 한 카메라 좌표계로 변환하는 것을 말한다.

 

 

* 프로젝션(투영)

월드와 카메라는 모두 3차원 좌표계이다. 그러나 모니터를 통해 보는 화면은 실제로 2차원 화면이다. 그래서 3차원 좌표계를 2차원으로 바꿔주는 것이 필요하다. 이를 투영변환(Projection Transform)이라 한다.

 

3차원 자표계를 2차원 좌표계로 변환하는 가장 쉬운 방법은 한 축을 없애는 것이다. 모든 정점의 Z값을 0으로 하면 결과적으로 x, y만 남기 때문에  자연스럽게 2차원 좌표계로 반환되는 셈이다 이런 변환을 직교투영(orthographic projection)이라고 하며 이런 기법은 CAD나 CAM에서 사용한다.

실제 D3D에서 많이 사용하는 기법은 원근투영(persperctive projection)기법으로 카메라의 거리에 따라 투영되는 비율이 달라지는 방법이다.

 
카메라 좌표계의 절두체(frustum) 공간이 투영 변환 후에는 (-1,-1,0)~(1,1,1) 크기의 사각 입방체 공간으로 변형된다.
여기서 Z값 ( 0.0~1.0)의 Z값은 흔히 우리가 말하는 Z버퍼 값으로 사용되고, 나머지 X,Y값이 화면에 출력되는 값!!!!! 



사진 출저:한국콘텐츠 진흥원 아카데미 





<사진출저: 한국콘텐츠진흥원 아카데미>
 
 



//-----------------------------------------------------------------------------
// Name: SetupMatrices()
// Desc: Sets up the world, view, and projection transform matrices.
//-----------------------------------------------------------------------------

VOID SetupMatrices()
{

     // 월드행렬
    D3DXMATRIXA16 matWorld;

    //float연산의 정밀도를 위해서 1000으로 나머지연산
    UINT  iTime  = timeGetTime() % 1000;   
 

    //1000밀리초마다 한바퀴씩(2 * pi) 회전 애니메이션 행렬을 만든다.
    FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f; 
    D3DXMatrixRotationY( &matWorld, fAngle );    // Y축을 회전행렬 생성
 

    // 생성한 회전행렬을 월드행렬로 디바이스에 설정
    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); 
 

    /// 뷰행렬을 정의하기 위해서는 세가지값이 필요하다.    
    D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );            // 1. 눈의 위치( 0, 3.0, -5)
    D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );      // 2. 눈이 바라보는 위치( 0, 0, 0 )
    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );         // 3. 천정방향을 나타내는 업벡터( 0, 1, 0 )
    
    D3DXMATRIXA16 matView;     //행렬값하나 만듬
 

    // 1,2,3의 값으로 뷰행렬 생성
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); 
 

    // 생성한 뷰행렬을 디바이스에 설정
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );   
 

    // 프로젝션 행렬을 정의하기 위해서는 시야각(FOV=Field Of View)과 종횡비(aspect ratio),

    // 클리핑 평면의 값이 필요하다.
    D3DXMATRIXA16 matProj;

    // matProj   : 값이 설정될 행렬
    // D3DX_PI/4 : FOV(D3DX_PI/4 = 45도)
    // 1.0f      : 종횡비
    // 1.0f      : 근접 클리핑 평면(near clipping plane)
    // 100.0f    : 원거리 클리핑 평면(far clipping plane)

    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
 

    // 생성한 프로젝션 행렬을 디바이스에 설정
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );  
}





행렬 변환 함수를 실제로 호풀하는 것은 Render() 함수이다 

//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------

VOID Render()
{

    /// 후면버퍼를 파란색(0,0,255)으로 지운다.
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,

                                  D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

    /// 렌더링 시작
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {

        /// 월드,뷰,프로젝션 행렬을 설정한다.
        SetupMatrices();
 

        /// 정점버퍼의 내용을 그린다.
        g_pd3dDevice->SetStreamSource( 0, g_pVB, 0,sizeof(CUSTOMVERTEX) );
 

        g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );

        g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );

          /// 렌더링 종료
        g_pd3dDevice->EndScene();
    }

    /// 후면버퍼를 보이는 화면으로!
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

 

TIP: 

DrawPrimitive()함수 전에 행렬을 설정해야 하므로 그 전에 SetupMatrices()를 호출하고 있다.
위 소스를 보다 최적화 한다면 BeginScene()함수 이전에 SetupMatrices()를 호출하는것이 도 효율적일 것이다. BeginScene()과 EndScene()사이는 짧을수록 효과적이다. 와우!!!!!!!!

 


D3DXMatrixRotationY(); 

y 축을 회전축으로 해 회전하는 행렬을 생성 한다.
 

구문

D3DXMATRIX *D3DXMatrixRotationY(      
    D3DXMATRIX *pOut,     FLOAT Angle );

파라미터

pOut
연산 결과인 D3DXMATRIX 구조체의 포인터.
 
Angle
회전의 각도 (라디안 단위). 각도는, 회전축을 중심으로 해 원점 방향을 향한 시계회전으로 측정한 것이다.

반환값

y 축을 회전축으로서 회전한 D3DXMATRIX 구조체의 포인터.




SetTransform()

단일 장치의 변환 관련 스테이트를 설정한다.
 

구문

HRESULT SetTransform(   
    D3DTRANSFORMSTATETYPE State,     CONST D3DMATRIX *pMatrix );

파라미터

State
변경 대상의 장치 스테이트 변수. 이 파라미터에는,D3DTRANSFORMSTATETYPE열거형의 임의의 멤버 또는 D3DTS_WORLDMATRIX 매크로를 지정할 수 있다.
 
pMatrix
현재의 변환을 변경하는 D3DMATRIX 구조체의 포인터.

반환값

성공했을 경우는, D3D_OK 를 돌려준다.

인수의 1 개가 무효인 경우는, D3DERR_INVALIDCALL 를 돌려준다




D3DXMatrixLookAtLH()
왼손 좌표계 뷰 행렬을 생성 한다.
 

구문

D3DXMATRIX *D3DXMatrixLookAtLH(      
    D3DXMATRIX *pOut,     
    CONST D3DXVECTOR3 *pEye,     
    CONST D3DXVECTOR3 *pAt,     
    CONST D3DXVECTOR3 *pUp );

파라미터

pOut
연산 결과인 D3DXMATRIX 구조체의 포인터.
pEye
시점을 정의하는 D3DXVECTOR3 구조체의 포인터. 이 값은, 평행이동에 사용된다.
pAt
카메라의 주시 대상을 정의하는 D3DXVECTOR3 구조체의 포인터.
pUp
현재 월드의 윗쪽, 일반적으로는 [0, 1, 0] 을 정의하는 D3DXVECTOR3 구조체의 포인터.

반환값

왼손 좌표계 뷰 행렬인 D3DXMATRIX 구조체의 포인터.


주의

이 함수의 반환값은,pOut 파라미터의 반환값과 같다.
따라서,D3DXMatrixLookAtLH함수를 다른 함수의 인수로서 사용할 수 있다.

이 함수가 돌려주는 행렬은, 다음 공식을 사용해 계산한다.

zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)

 xaxis.x           yaxis.x           zaxis.x          0
 xaxis.y           yaxis.y           zaxis.y          0
 xaxis.z           yaxis.z           zaxis.z          0
-dot(xaxis, eye)  -dot(yaxis, eye)  -dot(zaxis, eye)  1



D3DXMatrixPerspectiveFovLH()
시야에 근거해, 왼손 좌표계 퍼스펙티브 투영 행렬을 생성 한다.


구문

D3DXMATRIX *D3DXMatrixPerspectiveFovLH(      

    D3DXMATRIX *pOut,     
    FLOAT fovY,     
    FLOAT Aspect,     
    FLOAT zn,     
    FLOAT zf );

파라미터

pOut
연산 결과인 D3DXMATRIX 구조체의 포인터.
fovY
y 방향에의 시야 (라디안 단위).
Aspect
어스펙트비(가로세로 비율). 뷰 공간의 높이를 폭으로 나눗셈 한 값으로 정의된다.
zn
가까운 뷰 평면의 Z 값.(near)
zf  
먼 뷰 평면의 Z 값.(far)

반환값

왼손 좌표계 퍼스펙티브 투영 행렬인 D3DXMATRIX 구조체의 포인터.

주의

이 함수의 반환값은,pOut 파라미터의 반환값과 같다.
따라서,D3DXMatrixPerspectiveFovLH 함수를 다른 함수의 인수로서 사용할 수 있다.

이 함수가 돌려주는 행렬은, 다음과 같이 계산한다.

w       0       0               0
0       h       0               0
0       0       zf/(zf-zn)      1
0       0       -zn*zf/(zf-zn)  0
where:
h is the view space height.  It is calculated from 
h = cot(fovY/2);

w is the view space width.  It is calculated from
w = h / Aspect.

[출처] Matrices 기초|작성자 누리블루

이 글을 공유하기

댓글

Designed by JB FACTORY