ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DXUT Framework에서 카메라 설치하기
    정리필요2 2008. 7. 2. 18:59


    DXUT Framework에서 카메라 설치하기

    3D 프로그래밍을 입문하면서 처음에 제일 골아픈 것이 바로 카메라입니다. DXUT는 기본으로 제공하는 카메라가 있으며, 작은 설정으로 그럴듯한 카메라를 이용할 수 있게 해 줍니다. CFirstPersonCamera와 CModelViewerCamera의 두 가지를 제공합니다만, 여기서는 먼저 CModelViewerCamera의 설치법만을 소개합니다. CModelViewerCamera는 마우스 드래그를 통해 해당 위치 주위를 선회하는 카메라를 구현합니다.

    1. CModelViewerCamera를 모든 Callback 함수가 접근할 수 있는 위치에 지정합니다.

      이 예제에서는 전역에 선언하도록 하겠습니다.

      CModelViewerCamera g_Camera;
      	
    2. OnCreateDevice에 카메라를 설치합니다.

      이 카메라 객체는 단순히 계산만 해주는 객체입니다. 따라서 IDirect3DDevice를 이용하지 않기에 OnCreateDevice에서 초기화합니다.

      HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, 
      	const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
      {	
      	...
      	D3DXVECTOR3 vEye = D3DXVECTOR3( 0.0f, 0.0f, -5.0f );
      	D3DXVECTOR3 vLookAt = D3DXVECTOR3( 0.0f, 0.0f, -0.0f );
      	g_Camera.SetViewParams( &vEye, &vLookAt );
      	...
      }	
      	

      vEye는 카메라의 위치이고 vLookAt은 물체의 위치입니다. 이 카메라는 마우스 드래그를 통해 카메라의 위치만을 변경하고 항상 현재 설정한 물체의 위치를 바라봅니다.

    3. MsgProc에서 입력을 받아 FrameMove에서 카메라의 위치를 계산합니다.

      MsgProc에서 입력을 알맞은 카메라 행동으로 바꾸어주고, 실제 계산은 FrameMove에서 하게 됩니다.

      LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
      	bool* pbNoFurtherProcessing, void* pUserContext )
      {
      	...
      	g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
      	...
      }
      	
      void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, 
      	double fTime, float fElapsedTime, void* pUserContext )
      {
      	...
      	g_Camera.FrameMove( fElapsedTime );
      	...
      }	
      	
    4. FrameRender에서 계산된 행렬을 적용합니다.

      카메라는 IDirect3DDevice를 직접 지닌 것이 아니라 사용자가 직접 계산결과를 적용해주는 것이 필요합니다.

      내용추가 :

      Projection은 OnResetDevice 때마다, World, View는 FrameMove떄마다 호출해도 됩니다. Projection은 Aspect Ratio, 즉 스크린의 가로세로비가 바뀔 때만 그 행렬이 달라지게 되고, World, View는 카메라의 위치 혹은 방향이 바뀌지 않는 한 변경되지 않기 떄문입니다.

      참고로 카메라의 정보를 설정하는 내용도 OnResetDevice에 추가하였습니다.

      HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
      	const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
      {
      	...
      	// Setup the camera's projection parameters
      	float fAspectRatio = pBackBufferSurfaceDesc->Width 
      		/ (FLOAT)pBackBufferSurfaceDesc->Height;
      	g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
      	g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, 
      		pBackBufferSurfaceDesc->Height );	
      	V( pd3dDevice->SetTransform( D3DTS_PROJECTION, g_Camera.GetProjMatrix() ) );	...
      }
      
      void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, 
      double fTime, float fElapsedTime, void* pUserContext ) { ... V( pd3dDevice->SetTransform( D3DTS_WORLD, g_Camera.GetWorldMatrix() ) ); V( pd3dDevice->SetTransform( D3DTS_VIEW, g_Camera.GetViewMatrix() ) ); ... }

      각각의 물체에 대해 세계 좌표를 부여하였다면, 카메라의 WorldMatrix에 각 물체의 WorldMatrix를 곱해주어야 합니다. 단 카메라의 WorldMatrix가 먼저 적용되어야 하므로 뒤에 곱해주어야 합니다. 즉, 카메라의 WorldMatrix를 Mw, 물체의 WorldMatrix를 Mo라고 할 때, WorldMatrix = Mo * Mw이 되어야 합니다. 물체를 원점에 배치했다면 위의 예제대로만 하여도 무리없이 나옵니다.

    조금 많기는 합니다만 자원 획득 및 파괴를 제외하면 계산 및 적용만 호출해주면 되는 셈입니다. 3D Programming에 입문하면서 제일 어려운 내용이 카메라였는데, 그런 면에서 DXUT로 입문하면 이런 구현된 모듈이 있다는 것이 편한 듯 합니다. ( 문서가 적은게 흠입니다. )

    이 글은 DXUT Framework의 이용에 초점을 맞추었으므로, 따로 VertexBuffer나 IndexBuffer의 이용법에 대해서는 적지 않았습니다. 위의 내용은 책에도 많고 문서에도 많으니 잘 찾아서 적용해보세요. 기왕 이렇게 시작한 스터디 잘 따라노셔서 끝까지 갈 수 있었으면 좋겠습니다.


    출처 : http://digitz.tistory.com/tag/DirectX

Designed by Tistory.