여태까지 OpenGL를 사용하다가 DirectX를 공부하기 위해 많이 자료를 찾아봤다.
OpenGL를 했으니까 쉽게 하겠지라는 생각을 가졌지만 막상 닥쳐보니까 엄청 까다로왔다.
DirectX 나빠요. ㅠ.ㅠ
어려웠던게 초기화는 부분이 상당히 짜증났다. DX9.0 SDK에 들어있는 샘플은 대부분 닷넷샘플이고 대부분이 DXUT인가 (GLUT비슷한거 같다.)를 사용해서 초기화 하는거 즉 win32에서 하는 것들이었다. 그리고 DX8.0쪽하고 많이 바뀐것 같아서 버전상관없이 찾다보니 많이 헷갈렸다.
그럼 DX9.0 초기화 하는 방법을 알아보겠다.
1. DirectX 9.0 SDK를 설치한다. 설치가 되면 자동으로 vs6.0의 include와 lib에 경로가 추가된다.
2. MFC 프로젝트(SDI,MDI)를 만든다.
3. 필요한 header파일과 lib파일을 포함시킨다.
lib파일은 project setting에서도 추가할 수 있지만. 이렇게 코딩상에서 하는게 더 나은것 같다.
#include
#pragma comment(lib,"d3d9")
#pragma comment(lib,"d3dx9")
4. IDirect3D9를 생성하고 IDirect3DDevice9를 생성한다. 생성은 CView::OnCreate 혹은 CView::OnInitialUpdate해서 해주면 된다. 하지만 필자는 OnCreate에서 해주기를 권한다. 이유는 SDI구조에서는 New Document이벤트가 발생할때마다 OnInitialUpdate()함수가 호출되기 때문에 조심해야한다.
// 클래스 멤버변수로 선언
int vs;
LPDIRECT3D9 m_pDirect3D=NULL;
LPDIRECT3DDEVICE9 m_p3DDevice=NULL;
D3DPRESENT_PARAMETERS m_D3DParam;
// OnCreate 혹은 OnInitialUpdate 함수 내용
m_pDirect3D=Direct3DCreate9(D3D_SDK_VERSION);
D3DCAPS9 caps;
m_pDirect3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vs=D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vs=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
CRect client_rc=GetClientRect();
D3DDISPLAYMODE d3ddm;
m_pDirect3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );
m_D3DParam.Windowed = TRUE;
m_D3DParam.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_D3DParam.EnableAutoDepthStencil = TRUE;
m_D3DParam.AutoDepthStencilFormat = D3DFMT_D16;
m_D3DParam.hDeviceWindow = hWnd;
// Count가 0이면 1과 같다.
m_D3DParam.BackBufferCount = 0;
m_D3DParam.BackBufferWidth = d3ddm.Width ;
m_D3DParam.BackBufferHeight = d3ddm.Height;
if (m_pDirect3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,vs,&m_D3DParam, &m_p3DDevice )==S_FALSE)
{
m_VertexProcessing=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if (m_pDirect3D->CreateDevice( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, hWnd,vs,&m_D3DParam, &m_p3DDevice)==S_FALSE)
return FALSE;
}
여기서 주의할 점은 Window 모드일 경우의 세팅이라는 것이다. 우선 Window모드로 할려면
D3DPRESENT_PARAMETERS::Windowed를 TRUE로 하여야 하며
D3DPRESENT_PARAMETERS::BackBufferFormat은 D3DFMT_UNKNOWN
D3DPRESENT_PARAMETERS::BackBufferWidth,BackBufferHeight이것이 가장 헷갈리는 부분인데.
결론적으로 얘기하면 현재 해상도의 크기값을 입력해주는것이 가장 좋은 것 같다.
원래는 현재 창의 크기(클라이언트 영역)인데, 만약 창의 크기가 사용자의 의해 바뀌었을때, 고려를 해주어야 한다. 만약 BackBufferWidth와 BackBufferHeight를 생성할때 클라이언트의 크기로 하게되면 사용자의 의해 창의 크기가 변하였을 때, Stretching이 된다.
그래서 이거에 대한 간단한 해결방법은 현재 행상도의 크기를 지정하고, OnSize마다 ViewPort를 설정해주면 해결이 되는 것 같다.
5. CView::OnSize에서 SetViewPort를 해준다.
D3DVIEWPORT9 vp={0,0,cx,cy,0.f,1.f};
m_p3DDevice->SetViewport(&vp);
6. CView::OnEraseBkgnd에서
return CView::OnEraseBkgnd(pDC) => return false;
7. CView::OnDraw에서 그려준다.
m_p3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,clr,1.0f, 0 );
m_p3DDevice->BeginScene();
...... 그리는 루틴
m_p3DDevice->EndScene();
m_p3DDevice->Present(0,0,NULL,NULL);
Posted by chungki