CAFE

3D 게임 프로그래밍

1 강. Direct3D 기본 환경 만들기

작성자나우프로|작성시간16.06.29|조회수3,019 목록 댓글 3

 오키 유튜브 동영상 강의 주소

 (1) https://youtu.be/40mZ1TILXpE

 (2) https://youtu.be/qeny3jZNFhc

 (3) https://youtu.be/NvVSrRGs8PM

 (4) https://youtu.be/fjIbM_Zr91o

 

 !! 소스 코드는 자료실에 있습니다.

  

1.1 Win32 API 기본 코드 생성

 

(1) 엑셀레이더 코드 제거

 

 

Win32 API를 자동생성 코드로 생성하면 엑셀레이터 코드가 자동으로 붙게 된다.

이 코드를 제거하는 간단한 방법은 엑셀레이터 변수인 HACCEHACCEL hAccelTable;

를 제거하고 난 후에 Ctrl+F5f를 눌러 컴파일을 하면 에러나는 부분을 모두 삭제하면 간단히 해결된다.


(2) 메시지 루프


Win32 API 메시지 루프는 메시지가 있을 때 GetMessage()가 실행된다.

즉 GetMessage()는 응용프로그램에 해당되는 메시지를 조사하다가 메시지 발생하면 리턴하므로 GetMessage()는 대기상태를

만들게 된다.


게임은 계속적으로 업데이트와 렌더링을 반복주는 구조이므로 이 구조를 수정해야 한다.

PeekMesssage()는 대기상태 없이 메시지만을 체크해주거나 제거가 가능한 함수이므로 이 함수를 이용하여

아래와 같이 구조를 만든다.

 

while ( true )

{

    if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE) )

    {

       if( msg.message == WM_QUIT )

          break;

       TranslateMessage(&msg);

       DispatchMessage(&msg);

    }else{

       // 업데이트와 렌더링

 

    }

}


1.2 Direct3D 구조

 

[그림 1-1] Direct3D 그래픽 파이프라인 구조


[그림 1-2] Direct3D와 다른 시스템 컴포넌트와의 관계도


1) HAL(Hardware Abstraction Layer) Device와 Reference Device

 

HAL Device는 하드웨어의 엑셀레이트 기능을 지원하는 장치이며 라이팅과 변환등의 모든 기능을 실행할

수 있는 장치이다. 그리고 응용 프로그램에서는 직접적으로 그래픽 어텝터에 접근할 수가 없으므로

HAL Device를 통해 접근하게 된다.

Reference Device는 HAL Device에 비해 빠르지는 않지만 모든 Direct3D의 기능을 실행할 수 있는 장치이다.


1.3 Direct3D와 Direct3D Device의 초기화 및 생성


■ 기본 설정 사항


(1) Direct3D 라이브러리와 헤더 경로 등록


프로젝트 속성 창에서 헤더 경로와 라이브러리 경로를 아래와 같이 등록한다.


[그림 1-3] 디렉터리 속성창


 위의 속성에서 헤더와 라이브러이 등록하는 과정은 동영상 강의에 따라 설정한다.

  


(2) 포함 헤더

   d3d9.h


(3) 포함 라이브러리

   dxguid.lib, d3d9.lib, d3dx9.lib;


 비주얼 스튜디오에 라이브러리를 등록할 때는 ; (세미콜론)으로 구분하여 입력하며 링커에 라이브러리 등록하는 방법은 동영상 강의에 따라 설정한다.


■ Direct3D Device의 생성

 

(1) Direct3D와 Direct3D Device 변수


LPDIRECT3D9         g_pD3D = NULL;

LPDIRECT3DDEVICE9   g_pd3dDevice = NULL;


(2) Direct3D의 생성


IDirect3D9 * Direct3DCreate9(

    UINT SDKVersion

);


SDKVersion에는 D3D_SDK_VERSION을 사용한다.


LPDIRECT3D9 g_pD3D = NULL;

    

if( NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))

    return E_FAIL;


(3) Direct3D Device의 생성


HRESULT CreateDevice(

  [in]           UINT Adapter,

  [in]           D3DDEVTYPE DeviceType,

  [in]           HWND hFocusWindow,

  [in]           DWORD BehaviorFlags,

  [in, out]      D3DPRESENT_PARAMETERS *pPresentationParameters,

  [out, retval]  IDirect3DDevice9 **ppReturnedDeviceInterface

);


device 생성하기 위해서는 D3DPRESENT_PARAMETERS 구조체 변수를 사용한다.

이 구조체의 기본값은 0이며 필요한 부분만 설정하여 device를 생성한다.

 

 D3DPRESENT_PARAMETERS d3dpp;

 ZeroMemory( &d3dpp, sizeof( d3dpp ) );

 d3dpp.Windowed = TRUE;

 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

 

 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,

                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,

                                      &d3dpp, &g_pd3dDevice ) ) )

{

        return E_FAIL;

}


SwapEffect는 열거형 변수로써 페이지플리핑을 할 때 버퍼가 교환되는 방식을 설정한다.

사용하는 변수값으로 D3DSWAPEFFECT_FLIP, D3DSWAPEFFECT_COPY , D3DSWAPEFFECT_DISCARD 이 있으며

D3DSWAPEFFECT_DISCARD 가 가장 효율이 좋다.

 

 참고적으로 도큐멘트에서는 윈도우 모드일 때는 D3DSWAPEFFECT_FLIP을 설정하라고 되어 있지만 이와 같이 설정해도 무관하고 실제 튜토리얼에 D3DSWAPEFFECT_DISCARD로 설정되어 있으므로 이를 따르도록 한다.

 

위와 같이 윈도우 모드일 때는 BackBufferFormat를 D3DFMT_UNKNOWN 로 설정하여 현재 화면모드와 동일한

백버퍼를 생성하도록 한다.


(4) Direct3D 초기화에 관한 전체 소스 (윈도우 모드)

 

LPDIRECT3D9         g_pD3D = NULL; // Used to create the D3DDevice

LPDIRECT3DDEVICE9   g_pd3dDevice = NULL; // Our rendering device

 

HRESULT InitD3D( HWND hWnd )

{  

    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )

        return E_FAIL;

   

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory( &d3dpp, sizeof( d3dpp ) );

    d3dpp.Windowed = TRUE;

    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

 

    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,

                                     hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,

                                     &d3dpp, &g_pd3dDevice ) ) )

    {

        return E_FAIL;

    }  

 

    return S_OK;

}


(5) 렌더링


그래픽의 렌더링 방식은 이중버퍼링을 하며 먼저 백버퍼의 내용을 지우고 모든 출력을 백버퍼에 하게 된다.

이와같은 과정을 거친 후에 front 버퍼와 back 버퍼의 역할을 바꿔 화면에 다음 장면을 출력하게 된다.

이를 페이지플리핑(pageflipping)이라고 한다.


하나의 front buffer와 두 개의 back buffer


- 백버퍼 지우기


HRESULT Clear(

  [in]  DWORD Count,

  [in]  const D3DRECT *pRects,

  [in]  DWORD Flags,

  [in]  D3DCOLOR Color,

  [in]  float Z,

  [in]  DWORD Stencil

);


Count에는 지울 영역 배열인 pRects의 개수를 지정해 주지만 전체 영역을 지우므로 0을 설정한다.

pRect는 지울 영역을 나열한 배열의 포인터이지만 전체 영역이므로 NULL을 설정한다.

Flags에는 지우려는 대상을 설정하는데 여기서는 백버퍼를 지우므로 D3DCLEAR_TARGET로 설정한다.

Color에는 지울 색상값을 설정하는데  D3DCOLOR_XRGB() 매크로함수를 사용하여 0 ~ 255까지의 값을

red, green, blue 순으로 설정한다.

Z는 깊이버퍼를 설정하는 부분으로 1.0f로 설정하고 Stencil에는 0을 설정한다.


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


- device의 렌더링 준비와 종료


렌더링의 준비되었을 때 실제 3D 출력을 할 수 있으며 렌더링이 끝난 후에는 반드시 종료해야 한다.


// Begin the scene

g_pd3dDevice->BeginScene();

 

// 여기에 실제 렌더링 코드가 들어간다.

 

// End the scene

g_pd3dDevice->EndScene();


- 페이지플리핑


HRESULT Present(

  [in]  const RECT *pSourceRect,

  [in]  const RECT *pDestRect,

  [in]  HWND hDestWindowOverride,

  [in]  const RGNDATA *pDirtyRegion

);

 

위의 함수는 페이지플리핑을 하는 함수로써 위의 렌더링이 끝난 후에 실행하게 된다.

위의 기본값인 NULL로 매개변수를 설정하면 된다.


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


- 렌더링 전체 소스

 

VOID Render()

{

    if( NULL == g_pd3dDevice )

        return;

 

    // Clear the backbuffer to a blue color

    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ),

                           1.0f, 0 );

 

    // Begin the scene

    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )

    {

        // Rendering of scene objects can happen here

 

        // End the scene

        g_pd3dDevice->EndScene();

    }

 

    // Present the backbuffer contents to the display

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

}


(6) Direct3D Deivce와 Direct3D의 해제


Direct3D를 해제할 때는 먼저 device를 먼저 해제하고 direct3d system을 해제하면 된다.

만약 device를 통해 생성한 많은 객체가 있다면 객체를 먼저 해제한 후에 device를 해제하고 direct3d device를

해제한다. 해제에 관한 코드는 아래와 같다.


VOID Cleanup()

{

    if( g_pd3dDevice != NULL )

        g_pd3dDevice->Release();

 

    if( g_pD3D != NULL )

        g_pD3D->Release();

}


1.4 Direct3D 초기화 전체 소스


#include "stdafx.h"

#include "01CreateDevice.h"

#include <d3d9.h>

 

#define MAX_LOADSTRING 100

 

 

HINSTANCE hInst;

TCHAR szTitle[MAX_LOADSTRING];

TCHAR szWindowClass[MAX_LOADSTRING];

HWND g_hWnd;

 

LPDIRECT3D9         g_pD3D = NULL; // Used to create the D3DDevice

LPDIRECT3DDEVICE9   g_pd3dDevice = NULL; // Our rendering device

 

//

ATOMMyRegisterClass(HINSTANCE hInstance);

BOOLInitInstance(HINSTANCE, int);

LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM);

INT_PTR CALLBACKAbout(HWND, UINT, WPARAM, LPARAM);

 

HRESULT InitD3D( HWND hWnd )

{   

    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )

        return E_FAIL;

    

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory( &d3dpp, sizeof( d3dpp ) );

    d3dpp.Windowed = TRUE;

    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

  

    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,

                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,

                                      &d3dpp, &g_pd3dDevice ) ) )

    {

        return E_FAIL;

    }  

 

    return S_OK;

}

 

VOID Cleanup()

{

    if( g_pd3dDevice != NULL )

        g_pd3dDevice->Release();

 

    if( g_pD3D != NULL )

        g_pD3D->Release();

}

 

VOID Render()

{

    if( NULL == g_pd3dDevice )

        return;

 

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

 

    // Begin the scene

    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )

    {

       

        g_pd3dDevice->EndScene();

    }

 

    // Present the backbuffer contents to the display

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

}

 

int APIENTRY _tWinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPTSTR    lpCmdLine,

                     int       nCmdShow)

{

   UNREFERENCED_PARAMETER(hPrevInstance);

   UNREFERENCED_PARAMETER(lpCmdLine);

   MSG msg;

 

   LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

   LoadString(hInstance, IDC_MY01CREATEDEVICE, szWindowClass, MAX_LOADSTRING);

   MyRegisterClass(hInstance);

 

   if (!InitInstance (hInstance, nCmdShow))

   {

      return FALSE;

   }

 

   InitD3D( g_hWnd );   

 

   while (1)

   {

      if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE) )

      {

         if( msg.message == WM_QUIT )

            break;

 

         TranslateMessage(&msg);

         DispatchMessage(&msg);

      }else{

         

         Render();

      }

  }

  return (int) msg.wParam;

}

 

ATOM MyRegisterClass(HINSTANCE hInstance)

{

    WNDCLASSEX wcex;

     // 자동 생성 코드 그대로 놓음

     //.... 생략

 

    return RegisterClassEx(&wcex);

}

 

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

   HWND hWnd;

 

   hInst = hInstance;

 

   g_hWnd = hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

      100, 100, 300, 300, NULL, NULL, hInstance, NULL);

 

   if (!hWnd)

   {

      return FALSE;

   }

 

   ShowWindow(hWnd, nCmdShow);

   UpdateWindow(hWnd);

 

   return TRUE;

}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,

                               LPARAM lParam)

{

     int wmId, wmEvent;

     PAINTSTRUCT ps;

     HDC hdc;

 

     switch (message)

     {

        case WM_DESTROY:

               Cleanup();

               PostQuitMessage(0);

               break;

     default:

             return DefWindowProc(hWnd, message, wParam, lParam);

     }

     return 0;

}


[실행 결과]

 

좋은하루

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
  • 작성자Torvia | 작성시간 16.12.22 교수님의 강의 내용이 머리 속에 쏙쏙 들어오는 느낌이 들어서 정말 뿌듯하고 기분이 좋습니다.
  • 작성자우주악동 | 작성시간 16.12.30 win32project1direct\01createdevice.cpp(149): error C2065: 'IDC_MY01CREATEDEVICE': 선언되지 않은 식별자입니다. 란 에러만 자꾸뜨네요 올려주신 예제를 다운받아서 했는데도 문제가 생깁니다.
  • 작성자koramga | 작성시간 17.05.14 잘 배우고 있습니다. 정말로 감사합니다.
댓글 전체보기
맨위로

카페 검색

카페 검색어 입력폼