D3D10 Tutorial 00: Win32 Basics

D3D10 Tutorial 00: Win32 Basics

Reference >
    http://msdn2.microsoft.com/en-us/library/bb172484.aspx


Direct3D 10을 이용한 윈도우 어플리케이션을 만들기 위해서, 우선 모든 Win32 어플리케이션이 그러하듯이 윈도우 객체를 생성해야 합니다. 이번 튜토리얼에서는 Direct3D 10을 본격적으로 다루기에 앞서 먼저 다음 그림과 같이 비어있는 윈도우를 만드는 방법에 대하여 살펴보겠습니다.

이번 튜토리얼의 결과 스크린샷

윈도우를 생성하는 방법은 크게 3단계(윈도우 클래스 등록, 윈도우 객체 생성, 메시지 처리)로 나누어집니다. 우선 프로그램의 시작점인 WinMain함수를 살펴보겠습니다.
WinMain함수에 관하여 자세히 알고 싶으시면
 WinMain : http://winapi.co.kr/win32lec/lec2/lec2-2-1.htm

int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
    // 1. 윈도우 클래스 등록2. 윈도우 객체 생성
    if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
        return 0;

    // 3. 메시지 루프
    MSG msg = {0};
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }    return (int) msg.wParam;
}

1. 윈도우 클래스 등록

    // Register class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_TUTORIAL1);
    if( !RegisterClassEx(&wcex) )
    return FALSE;

윈도우 클래스에 관하여 자세히 알고 싶으시면
 윈도우 클래스 : http://winapi.co.kr/win32lec/lec2/lec2-2-2.htm

2. 윈도우 객체 생성

  // Create window
    g_hInst = hInstance; // Store instance handle in our global variable
    RECT rc = { 0, 0, 640, 480 };
    AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
    g_hWnd = CreateWindow( szWindowClass, L"Direct3D 10 Tutorial 0: Setting Up Window", WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL,
                           hInstance, NULL);

    if( !g_hWnd )
        return FALSE;

    ShowWindow( g_hWnd, nCmdShow );

윈도우 객체 생성에 관하여 자세히 알고 싶으시면
 윈도우 객체 생성 : http://winapi.co.kr/win32lec/lec2/lec2-2-2.htm (페이지하단)

3. 메시지를 받아서 처리

   // 메시지 루프
 MSG msg = {0};
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

메시지 루프에 관하여 자세히 알고 싶으시면
 메시지루프 : http://winapi.co.kr/win32lec/lec2/lec2-2-3.htm

 LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
 {
  PAINTSTRUCT ps;
  HDC hdc;
 
  switch (message)
  {
   case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    EndPaint(hWnd, &ps);
    break;
 
   case WM_DESTROY:
    PostQuitMessage(0);
    break;
 
   default:
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
 
  return 0;
 }

윈도우 프로시져(WndProc)에 관하여 자세히 알고 싶으시면
 윈도우 프로시져 : http://winapi.co.kr/win32lec/lec2/lec2-2-4.htm


위의 3가지 단계는 윈도우 객체를 생성하기 위하여 반드시 필요한 부분입니다. 코드에 관한 자세한 내용을 알고 싶으시면 윈도우 API책을 살펴보시기를 권해드립니다.

See Also >
    D3D10 튜토리얼 : http://hansnara.pe.kr/lifelog/hans/95
     Win32 API : http://winapi.co.kr

- by hans

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2007/08/06 21:42 2007/08/06 21:42
, , , , , , ,
Response
A trackback , No Comment
RSS :
http://hansnara.pe.kr/blog/rss/response/96

Trackback URL : http://hansnara.pe.kr/blog/trackback/96

Trackbacks List

  1. Direct3D 10 Tutorial List

    Tracked from hansObsession 2007/08/06 21:44 Delete

    Direct3D 10 Tutorial ListBasic Tutorials >D3D10 Tutorial 00: Win32 Basics ▶ http://hansnara.pe.kr/lifelog/hans/96D3D10 Tutorial 01: Direct3D 10 BasicsD3D10 Tutorial 02: Rendering a TriangleD3D10 Tutorial 03: Shaders and the Effect SystemD3D10 Tutor..

Leave a comment
[Login][OpenID?]

Direct3D 10 Tutorial List

Direct3D 10 Tutorial List

Basic Tutorials >
D3D10 Tutorial 00: Win32 Basics
      http://hansnara.pe.kr/lifelog/hans/96

D3D10 Tutorial 01: Direct3D 10 Basics
D3D10 Tutorial 02: Rendering a Triangle
D3D10 Tutorial 03: Shaders and the Effect System
D3D10 Tutorial 04: 3D Spaces
D3D10 Tutorial 05: 3D Transformation
D3D10 Tutorial 06: Lighting
D3D10 Tutorial 07: Texture Mapping and Constant

DXUT Tutorials >
D3D10 Tutorial 08: Introduction to DXUT
D3D10 Tutorial 09: Meshes in DXUT
D3D10 Tutorial 10: Advanced DXUT

Shader Tutorials >
D3D10 Tutorial 11: Vertex Shaders
D3D10 Tutorial 12: Pixel Shaders
D3D10 Tutorial 13: Geometry Shaders

State Tutorials >
D3D10 Tutorial 14: State Management

Reference
>

     http://msdn2.microsoft.com/en-us/library/bb205281.aspx

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2007/08/06 21:41 2007/08/06 21:41
, , , , , , ,
Response
A trackback , a comment
RSS :
http://hansnara.pe.kr/blog/rss/response/95

Trackback URL : http://hansnara.pe.kr/blog/trackback/95

Trackbacks List

  1. D3D10 Tutorial 00: Win32 Basics

    Tracked from hansObsession 2007/08/06 21:43 Delete

    D3D10 Tutorial 00: Win32 BasicsReference ▶ http://msdn2.microsoft.com/en-us/library/bb172484.aspxDirect3D 10을 이용한 윈도우 어플리케이션을 만들기 위해서, 우선 모든 Win32 어플리케이션이 그러하듯이 윈도우 객체..

Comments List

  1. Naivegal 2009/08/18 01:37 # M/D Reply Permalink

    how to read text file in directx 10??

Leave a comment
[Login][OpenID?]

D3D Tutorial 1: Create a Device

디바이스 생성

//-----------------------------------------------------------------------------
// 전역변수
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D       = NULL; // D3D 디바이스를 생성할 D3D객체 변수
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // 렌더링에 사용될 D3D디바이스


다른 함수들에서 사용할 수 있도록 전역변수로 선언한다.
g_pD3D는 D3D를 초기화하고 릴리즈 할 때만 사용된다.
렌더링과 관련된 부분은 모두 g_pd3dDevice를 이용하게 된다.
LPDIRECT3D9와 LPDIRECT3DDEVICE9 에서 LP는 long pointer를 의미하고
각각은 IDirect3D9* IDirect3DDevice9* 와 같다
여기서 I는 Component Object Model (COM)의 interface 임을 의미한다.


프로그램이 시작될때 가장 먼저 실행되는 함수인 WinMain()을 살펴보자.

//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: 프로그램 진입점
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
  // 윈도우 클래스 정의, 등록
  WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                     GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                     "D3D Tutorial", NULL
  RegisterClassEx( &wc );

  // 윈도우 생성
  HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 01: CreateDevice",
                             WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                             NULL, NULL, wc.hInstance, NULL );

  // Direct3D 초기화
  if( SUCCEEDED( InitD3D( hWnd ) ) )
  {
       // 윈도우 출력
       ShowWindow( hWnd, SW_SHOWDEFAULT );
       UpdateWindow( hWnd );

       // 메시지 루프
       MSG msg;
       while( GetMessage( &msg, NULL, 0, 0 ) )
       {
           TranslateMessage( &msg );
           DispatchMessage( &msg );
       }
  }

  // 등록된 클래스 소거
  UnregisterClass( "D3D Tutorial", wc.hInstance );
  return 0;
}


어떻게 동작하는지 간단히 살펴보면...

1. 윈도우 클래스를 등록하고 윈도우 생성
2. Direct3D를 초기화 한다.
3-2. 초기화에 실패하면 등록된 윈도우 클래스를 없애고
    프로그램이 종료된다.
3-1. 초기화가 제대로 되었으면
    윈도우를 출력하고 메시지루프를 계속 돌면서
    메시지를 처리한다.
    종료메시지가 들어오면 루프를 빠져나오게 된다
4. 등록된 윈도우 클래스를 없애고 프로그램이 종료된다.

대략 이런 순서로 실행이 된다.

대부분의 내용이 윈도우즈 프로그래밍을 해봤다면
이해가 될 것이다. 아니면 API책을 보는것도 괜찮겠다.


InitD3D()부분을 살펴보도록 하자.

//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: D3D초기화
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
  // D3D디바이스 생성을 위한 D3D객체 생성
  if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
       return E_FAIL;

  D3DPRESENT_PARAMETERS d3dpp;                  // 디바이스 생성을 위한 구조체
  ZeroMemory( &d3dpp, sizeof(d3dpp) );          // 구조체를 0으로 채움
  d3dpp.Windowed = TRUE;                        // 창모드
  d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;     // 가장 효율적인 swap효과
  d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;      // 현재 바탕화면 모드에 맞추어 백버퍼생성


  // 디바이스 생성
  // 1. 디폴트 비디오카드를 사용 (대부분은 비디오카드가 한 개다)
  // 2. HAL  (HW 가속 장치를 사용하겠다는 의미)
  // 3. 정점 처리는 모든 카드에서 지원하는 SW 처리로 생성한다 (HW로 생성할 경우 더욱 높은 성능을 낸다.)
  if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                     D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                     &d3dpp, &g_pd3dDevice ) ) )
  {
       return E_FAIL;
  }

  // 디바이스 상태 정보를 처리할 경우 여기에서 한다

  return S_OK;
}

1. D3D 객체 생성
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )
SDK의 버전에 맞게 헤더파일이 사용되고 있음을 알려준다.
버전이 일치하지 않으면 NULL을 리턴하게 된다.
제대로 되었으면 g_pD3D에 d3d객체가 저장되는데
이것은 d3d디바이스를 생성하는데 사용한다.
잊지말고 프로그램을 종료하기 전에 릴리즈해줘야 한다.

2. Presentation 셋팅
D3DPRESENT_PARAMETERS d3dpp;
디바이스를 어떻게 생성할지 정보를 담는 구조체이다
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp 안에는 여러가지 설정해줄 수 있는것들이 많으므로 0으로 초기화 한다

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
백버퍼는 렌더링될 화면(컬러)이 저장되는 버퍼로
D3DFMT_UNKNOWN로 하면 포맷을 바탕화면 모드에 맞게 한다.
바탕화면 모드는 디스플레이 등록정보에 보면
색품질에 무슨컬러 몇비트 이렇게 나오는걸 이야기 하는 듯하다
창모드로 띄울경우에 그렇고.. 풀스크린으로 하고싶으면
d3dpp.Windowed = FALSE;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
이와같이 A,R,G,B 각 8비트씩 32비트로 해주거나 혹은 용도에 맞게
설정해주면 될 것이다.
그러나 역시 게임을 개발할때에는 창모드로 해놓고 개발하는것이 편하다.

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
컬러를 나타내는 버퍼에는 역할상 백버퍼와 프론트버퍼로 나눌 수 있다.
백버퍼는 렌더링하는 버퍼이고 프론트 버퍼는 현재 화면에 보여지는 버퍼이다
버퍼를 한개 이용하는 경우 한장 렌더링하고 다 지우고 다시 렌더링하게 되므로
깜빡깜빡하는 것 처럼 보이게 된다. 그러나 버퍼를 두개를 두어서(더블버퍼링)
실제 렌더링은 화면에 보이지 않는 백버퍼에 그린후에 렌더링이 다 되면
프론트 버퍼에 옮겨서(swap) 화면에 보이게 하는것이다.
스왑하는 방법에는 크게 두가지 있는데 백버퍼의 값을 프론트 버퍼에
카피(D3DSWAPEFFECT_COPY)하는 방법과 백버퍼와 프론트 버퍼의 역할을
서로 바꾸는 것(D3DSWAPEFFECT_FLIP)이다.
D3DSWAPEFFECT_DISCARD로 해주면 상황에 맞게 알아서 잘 해준다.
자세한 내용은 DirectX 도움말을 보자.
d3dpp.BackBufferCount를 이용하면 생성되는 백버퍼의 개수를
설정해 줄 수 있다.이때 백버퍼의 집합을 스왑체인(swap chain)이라고 한다.
일반적으로 백버퍼 개수라고 하면 프론트 버퍼의 개수까지 포함한다.
그냥 컬러버퍼의 개수라고 생각하면된다.
백버퍼중 하나가 화면에 보여지게 될 경우 그것을 프론트버퍼이다

프레임수가 고정되어있는 경우, 대개 60..
이 경우는 화면의 주사율(60Hz)에 맞추어서 화면을 갱신(스왑)하기 때문이다.
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
이렇게 해주면 화면 주사율과 상관없이 기다리지 않고 바로바로 그려지게된다.
풀스크린에서 볼 때는 주사율에 맞추어서 화면이 갱신되는게
오히려 더 자연스럽게 보인다.

이외에도 설정할 수 있는것이 더 많이 있으니
DirectX 도움말을 참고하는것이 좋겠다.

3. D3D 디바이스 생성
g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice )
D3DADAPTER_DEFAULT - 디폴트 비디오카드를 사용 (대부분은 비디오카드가 한 개다)
D3DDEVTYPE_HAL - (HW 가속 장치를 사용하겠다는 의미)
D3DCREATE_SOFTWARE_VERTEXPROCESSING - 정점 처리는 모든 카드에서 지원하는 SW 처리로 생성한다
(D3DCREATE_HARDWARE_VERTEXPROCESSING 로 생성할 경우 더욱 높은 성능을 낸다.)
디바이스 생성이 제대로 되면 g_pd3dDevice 에 저장이 된다.
앞으로 렌더링과 관련된 부분은 모두 g_pd3dDevice를 이용하게 된다.
프로그램을 종료하기 전에 g_pd3dDevice를 반드시 릴리즈 해줘야함을 잊지 말자.


여기까지 무사히 다 성공했다면 S_OK를 리턴한다.
이제 다시 WinMain()으로 돌아가면..

  // Direct3D 초기화
  if( SUCCEEDED( InitD3D( hWnd ) ) ) // 성공!
  {
       // 윈도우 출력
       ShowWindow( hWnd, SW_SHOWDEFAULT );
       UpdateWindow( hWnd );

       // 메시지 루프
       MSG msg;
       while( GetMessage( &msg, NULL, 0, 0 ) )
       {
           TranslateMessage( &msg );
           DispatchMessage( &msg );
       }
  }

초기화를 성공했으므로 윈도우를 출력하고
메시지 루프를 계속 돌면서 들어오는 메시지를 처리한다.
DispatchMessage()가 MsgProc()을 호출하여 메시지를 처리하게된다.
어떻게 메시지를 처리하는지 MsgProc()을 따라가 보자.


//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: 윈도우 메시지 핸들러
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
  switch( msg )
  {
       case WM_DESTROY:
           Cleanup();
           PostQuitMessage( 0 );
           return 0;

       case WM_PAINT:
           Render();
           ValidateRect( hWnd, NULL );
           return 0;
  }

  return DefWindowProc( hWnd, msg, wParam, lParam );
}


WM_DESTROY 메시지는 윈도우가 종료될때, 종료버튼을 클릭하였을때 발생한다
그러면, Cleanup() 함수를 호출한다. 그런후에 PostQuitMessage()를 호출함으로
다음 메시지 루프가 실행되지 않고 프로그램이 종료된다.

WM_PAINT 메시지는 다시 그려져야할 필요가 있을때,
다른창에 가려졌다 나타날때, 최소화했다가 다시 창을 띄울때 등 발생한다
그러면, Render() 함수를 호출한다.

지금과 같은 경우, WM_PAINT가 발생할때 한 번 렌더링되고 화면이 전혀 갱신되지 않는다.
그러나 게임에서는 WM_PAINT 메시지와 상관없이 화면이 계속 갱신되어야 한다.
따라서 이 위치에 Render()가 들어가는 것은 적절하지 않다.
WinMain()의 루프 안에 위치하는 것이 적절하며 다음과 같은 스타일로 바꾸면 좋겠다.


InitD3D( hWnd ); // 초기화

// 메시지 루프 for game
while(1) {
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // 메시지 처리
          if(msg.message == WM_QUIT)
               break;
          TranslateMessage(&msg);
          DispatchMessage(&msg);
    } else {
          Render();  // 렌더링
    }
}

Cleanup(); // 릴리즈


어쨌든 Render()함수와 Cleanup()함수를 마저 따라가 보자

//-----------------------------------------------------------------------------
// Name: Render()
// Desc: 화면 그리기
//-----------------------------------------------------------------------------
VOID Render()
{
  if( NULL == g_pd3dDevice )
       return;

  // 백버퍼를 파란색으로 지운다.
  g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
 
  // 렌더링시작
  if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
  {
       // 렌더링할 오브젝트들이 이곳에
 
       // 렌더링 끝
       g_pd3dDevice->EndScene();
  }

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

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
위의 코드는 현재 렌더타겟으로 지정되어있는 D3DCLEAR_TARGET 버퍼(백버퍼,컬러버퍼)를
컬러는 D3DCOLOR_XRGB(0,0,255) 파란색으로 클리어하게 한다.

조금 더 일반적으로는 백버퍼와 함께 Z버퍼(깊이버퍼)를 같이 클리어한다.
D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER 이와같이 써주면
백버퍼는 뒤따라 이어나오는 인자인  D3DCOLOR_XRGB(0,0,255)로 클리어하고
Z버퍼는 1.0f로 클리어한다(값의 범위는 0.0f~1.0f).
Z버퍼에 관하여 자세한 내용은 이후 튜토리얼에 나오므로 그 부분에서 다루어 질 것이다.

D3DCOLOR_XRGB(0,0,255) 는 전처리기에 의하여 0xFF0000FF과 같이 바뀌어 컴파일된다.
따라서 D3DCOLOR_XRGB(0,0,255) 대신 0xFF0000FF를 사용하여도 좋다.
0xFF0000FF의 타입은 DWORD 로 이는 다시 D3DCOLOR 로 타입이 재정의 되어있다.
typedef DWORD D3DCOLOR
0xFF0000FF는 앞에서부터 두자리씩 끊어서 알파(A),레드(R).그린(G),블루(B)의 16진수 값을
의미한다.
색깔과 관련한 매크로로 자주 사용하는 것은
D3DCOLOR_XRGB(r,g,b)이외에도 D3DCOLOR_ARGB(a, r, g, b) 정도가 있다.
a,r,g,b 각각의 값은 0~255까지의 정수로 표현하며 0.0f~1.0f의 실수로 표현 할 경우에는
D3DCOLOR_COLORVALUE(r,g,b,a) 를 사용하면 된다.

각각의 매크로 정의는 다음과 같다.
#define D3DCOLOR_ARGB(a,r,g,b) \
  ((D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
#define D3DCOLOR_RGBA(r,g,b,a) D3DCOLOR_ARGB(a,r,g,b)
#define D3DCOLOR_XRGB(r,g,b)   D3DCOLOR_ARGB(0xff,r,g,b)

#define D3DCOLOR_COLORVALUE(r,g,b,a) \
  D3DCOLOR_RGBA((DWORD)((r)*255.f),(DWORD)((g)*255.f),(DWORD)((b)*255.f),(DWORD)((a)*255.f))

g_pd3dDevice->BeginScene() 는 렌더링의 시작을 그래픽카드(GPU)에게 알려주고
g_pd3dDevice->EndScene() 는 렌더링의 끝을 알려준다.
BeginScene()과 EndScene()은 반드시 쌍으로 이루어지며
어느하나가 빠져서도 안된다.
렌더링 코드들은 BeginScene()과 EndScene() 사이에 위치해야 제대로 렌더링이 되며
BeginScene()과 EndScene() 사이에는 되도록이면 계산하는 코드들을
넣지 않는것이 좋다.

지금 살펴보고 있는 함수는 Render()함수이다. 렌더링에 관련된 코드들이 모아져있는
함수임을 이름만으로도 알수 있다. 이부분에서 실제적으로 렌더링코드와 관련이 없는
게임등에서의 여러가지 처리와 계산이 필요한 것들은 별도로 함수를 만들어서
Render()함수를 호출하기 전에 그 함수를 호출하면 될것이다.

예를들면 아래와 같은 스타일로 할 수 있겠다.
while(1) {
         // 메시지처리
         Process();  // 매프레임 계산이나 처리가 필요한 것들은 모두 이곳에서 한다.
         Render();  // 실제 렌더링 코드들이 여기에 있다.
}
이렇게 따로 나눈 이유는 이후에 다시 살펴보기로 하자.

마지막으로 Cleanup()함수를 살펴보자.
이 함수는 종료메시지가 들어왔을때 실행되는데 InitD3D()함수와 짝을이루어
InitD3D()에서 생성한 것들을 릴리즈해주고 있다.

//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: 초기화된 객체들을 릴리즈
//-----------------------------------------------------------------------------
VOID Cleanup()
{
  if( g_pd3dDevice != NULL)
       g_pd3dDevice->Release();

  if( g_pD3D != NULL)
       g_pD3D->Release();
}

초기화 할때 g_pD3D, g_pd3dDevice의 순으로 초기화 해주었으므로
이것의 역순으로 릴리즈해줘야 문제가 없다.

SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pD3D);

SAFE_RELEASE 매크로가 정의 되어 있다면 위와같이 쓰는것이 편하고 좋다.
자주 유용하게 쓰는 매크로는 다음과 같다..

#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }

장황하게 길게 설명했다.. 쓸모없는 이야기들도 많고.
잘못된 부분도 있을것이다.
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2006/05/16 02:48 2006/05/16 02:48
, , , ,
Response
A trackback , No Comment
RSS :
http://hansnara.pe.kr/blog/rss/response/75

Trackback URL : http://hansnara.pe.kr/blog/trackback/75

Trackbacks List

  1. Direct3D Tutorial List

    Tracked from hansObsession 2006/05/16 03:35 Delete

    Direct3D Tutorial List Basic > D3D Tutorial 1: Create a Device ▶ http://blog.naver.com/narsislegend/20023882433 ▶ http://hansnara.pe.kr/lifelog/hans/75 D3D Tutorial 2: Rendering Vertices D3D Tutorial 3: Using Matrices D3D Tutorial 4: Creating and Usin

Leave a comment
[Login][OpenID?]

Direct3D Tutorial List

Direct3D Tutorial List

Basic >
D3D Tutorial 1: Create a Device
      http://blog.naver.com/narsislegend/20023882433
      http://hansnara.pe.kr/lifelog/hans/75

D3D Tutorial 2: Rendering Vertices
D3D Tutorial 3: Using Matrices
D3D Tutorial 4: Creating and Using Lights
D3D Tutorial 5: Using Texture Maps
D3D Tutorial 6: Using Meshes

Extra >
D3D Tutorial 7: Rendering Vertices with Index Buffer
D3D Tutorial 8: Framework with Simple Sample

Tool >
Visual Studio .NET 2003 with DirectX SDK (April 2006)

Reference >
     http://blog.naver.com/young2407/140015379428
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2006/05/04 17:30 2006/05/04 17:30
, , ,
Response
2 Trackbacks , No Comment
RSS :
http://hansnara.pe.kr/blog/rss/response/64

Trackback URL : http://hansnara.pe.kr/blog/trackback/64

Trackbacks List

  1. Tutorial1

    Tracked from narsislegend님의 블로그 2006/05/07 21:08 Delete

    처음꺼 올렸어!! ㅋㅋ 원래 했던거에 조금 수정했음!!

  2. D3D Tutorial 1: Create a Device

    Tracked from hansObsession 2006/05/16 03:16 Delete

    디바이스 생성//----------------------------------------------------------------------------- // 전역변수 //----------------------------------------------------------------------------- LPDIRECT3D9 g_pD3D = NULL; // D3D 디바이스를 생성할

Leave a comment
[Login][OpenID?]

팀컬러 (Team Color)

3D 모델에 팀 컬러를 입히는 방법

1. 색깔별로 텍스쳐를 모두 제작

장점 : 디자이너 마음대로 색깔을 제작할 수 있으며 별다른 구현이 필요없다.
단점 : 텍스쳐 메모리를 많이 차지하고 자원관리의 효율성이 떨어짐..
디자인팀에서 텍스쳐 관리가 힘들고 유지보수하기도 힘들다 (캐릭터별로, 색깔별로 텍스쳐를 모두 제작해야하므로)


2. 폴리곤을 재질의 색으로 칠함 (Polygon Tinting)

방법 : 팀컬러가 들어가지 않는 부분과 팀컬러가 들어가는 부분으로 나누어서 렌더한다. 팀컬러가지 않는 부분은 기존의 텍스쳐를 이용하고 팀컬러가 들어갈 부분에는 재질(Diffuse Color)를 설정하여 렌더한다.

1) 재질을 흰색으로 초기화
2) 팀컬러가 들어가지 않는 부분은 기존과 같이 렌더
3) 재질(Diffuse Color)을 원하는 색으로 설정
3) 팀컬러가 들어가는 부분을 렌더

장점 : 팀컬러를 위한 별도의 텍스쳐 제작이 필요없음
단점 : 두번 Draw Call하므로써 성능저하가 일어남
팀컬러가 들어가는 부분에서(텍스쳐+팀컬러색이 동시에 한 폴리곤에서 나타나야하는 경우) 디자이너의 의도대로 표현하기 쉽지 않음


3. 멀티텍스쳐를 이용한 텍스쳐 마스킹

방법 : 알파채널을 이용하여 팀컬러가 들어가지 않는 부분과 팀컬러가 들어가는 부분으로 나누어 렌더한다 팀컬러가 들어가지 않는 부분은 텍스쳐 색으로 렌더하고, 팀컬러가 들어가는 부분은 TFACTOR 색으로 렌더한다.

장점 : 디자인팀에서 알파채널을 이용하여 마음대로 제어 가능하며, 알파채널을 이용하므로 텍스쳐가 추가로 필요하지않다
단점 : 알파채널을 마스킹하는데 이용하므로 팀색상과 투명효과를 동시에 사용할 수 없다.


4. 멀티패스를 이용한 텍스쳐 마스킹

방법 : 처음에는 그냥 렌더한다(1st-pass). 그다음에는 메쉬의 색을 원하는 색로 수정하고, 텍스쳐의 알파채널의 투명도가 존재하는 부분만 렌더한다(2nd-pass)

장점 : 멀티텍스쳐를 이용한것과 같은 장점을 가진다.
단점 : 두번 렌더되고, 그 사이에 렌더상태가 변하기 때문에 성능저하가 발생한다.


5. 픽셀쉐이더를 이용한 텍스쳐 마스킹
(생략)



구현예 : 오버라이드 컬러(Override Color)를 이용한 팀컬러


오버라이드컬러 적용하여 캐릭터 색 변경 (사용자가 임의의 색으로 설정 가능)

원본 이미지 사이즈로 보려면 이미지를 클릭하세요


오버라이드컬러를 이용한 팀컬러

원본 이미지 사이즈로 보려면 이미지를 클릭하세요


기존의 텍스쳐(디퓨즈텍스쳐)에서 일정영역(알파채널을 마스크로이용) 새로운 색(TFACTOR)으로 덧씌워서 렌더링하는 방식이다. 최종적인 목표로 마비노기의 염색 시스템(사용자가 옷의 원하는 부분을 원하는 색으로 염색 가능)을 고려하여 구현하였음.


디퓨즈텍스쳐 - 임의의 색과 합쳐짐

알파채널 - 색이 섞이지 않는 부분



디퓨즈텍스쳐(회색톤의 기본텍스쳐, diffuse texture)에서 알파값이 없는 부분이 팀컬러가 들어가는 부분이고 알파값이 있는 부분이 팀컬러가 없는 부분이다.

즉,디퓨즈 텍스쳐에서 알파값이 있는 부분은 '텍스쳐의 색'으로 렌더되고, 알파값이 없는 부분은 '텍스쳐의 색 + 팀컬러' 로 렌더링된다.

수식으로 써보자면
Arg1 * Alpha + (Arg1 + Arg2 - 0.5) * (1 - Alpha)
Arg1은 텍스쳐, Arg2는 팀컬러


위에서 제시한 방법중 3번 방식으로

0번 Texture state 를
COLOROP, BLENDTEXTUREALPHA
COLORARG1, TEXTURE
COLORARG2, TFACTOR
ALPHAOP, DISABLE

위와 같이 설정하였음, 수식으로는 다음과 같다
Arg1 * Alpha + Arg2 * (1 - Alpha)

이는 팀컬러가 들어가는(알파값이 없는,0인) 부분에서 디퓨즈텍스쳐의 값이 무시되고, TFACTOR컬러로 모두 채워지게 된다. 그러나 원하는 것은 알파값이 없는 부분도 디자이너에 의하여 색이 적당히 제어되는 것이다. 즉, 팀컬러가 들어가는 부분에 Photoshop의 overlay기능(layer blending option중 하나)과 같이 디퓨즈텍스쳐값과 TFACTOR를 합한 값으로 보이게 하고 싶은 것이다. 따라서 Texture Unit(Texture Stage)을 한번 더 거치든지 아니면 한번 더 렌더해주는(2-pass) 방법을 이용하여 위와같은 효과를 내려고 한다.

현재 1번 Texture Unit(Texture Stage)은 Toon Shading(음영)을 위해 사용하고 있고, 최대 사용가능 Texture Unit의 개수를 2개까지로 제한했기 때문에 위와같은 효과를 위해서 다시한번 렌더해주는 2-pass방식을 택했다. 사용가능한 Texture Unit의 개수에 제한이 없다면 2-pass보다는 Texture Unit을 한 번 더 거치는 방법이 속도가 훨씬 빠를 것이다.


1) 1st Pass (텍스쳐의 색에 TFACTOR를 더한 색을 렌더)
0번 Texture state
COLOROP, ADDSIGNED
COLORARG1, TEXTURE
COLORARG2, TFACTOR
ALPHAOP, DISABLE

1번 Texture state : 툰쉐이딩

2) 2nd Pass (텍스쳐의 알파값이 존재하는 부분을 다시 렌더)
COLOROP, SELECTARG1
COLORARG1, TEXTURE
ALPHAOP, SELECTARG1
ALPHAARG1, TEXTURE


1번째 패스에서는 알파값에 관계없이 무조건 텍스쳐색과 팀컬러를 합한 값으로 렌더한다. 알파값이 있는 부분까지 팀컬러가 더해진 색이 나오기 때문에 알파값이 있는 부분만 다시한번 원래의 텍스쳐 색으로 덮어 씌운다.

분명 더 좋은 나은 방법이 있으리라 생각되지만 일단는 이렇게 구현했다.


단계별 캐릭터 변신과정

디퓨즈텍스쳐



디퓨즈텍스쳐+오버라이드컬러



디퓨즈텍스쳐+오버라이드컬러+툰쉐이딩



디퓨즈텍스쳐+오버라이드컬러+툰쉐이딩+외곽선



디퓨즈텍스쳐+오버라이드컬러+툰쉐이딩+외곽선+그림자

원본 이미지 사이즈로 보려면 이미지를 클릭하세요
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2006/01/25 14:45 2006/01/25 14:45
, ,
Response
No Trackback , No Comment
RSS :
http://hansnara.pe.kr/blog/rss/response/16

Trackback URL : http://hansnara.pe.kr/blog/trackback/16

Leave a comment
[Login][OpenID?]

스카이 박스 (Skybox)

맥스의 환경맵을 이용한 스카이 박스 만들기

Sky box는 의외로 간과하기 쉬운 부분이기도 하지만 이미지 왜곡 없이 제작하기가 생각보다 까다로운 점이 있습니다. 반구의 형태로 만들어도 되지만 게임을 만들때 극한의 리소스 싸움이 시작되면 반구의 페이스도 아쉽게 되죠. 그럴때 대부분 프로그램팀에 의해서 skybox를 제작하게 되지만 정확한 스카이박스를 맞추는 그래픽 맵소스를 제작하기까진 생각보다 시간이 걸리곤 합니다. 보통의 게임에선 몇몇가지의 정해진 패턴대로의 스카이박스 이미지를 사용하여 제작하곤하지만 그래픽디자이너가 원하는 깊이있는 스카이박스를 마음대로 제작하기란 생각보다 쉽지 않죠. 특별한 느낌의 하늘이미지를 사용하고 싶을때 맵에디터가 없거나 맥스상에서 최소의 리소스로 스카이박스를 제작하고자 할때 맥스의 환경맵을 직접 박스에 투영해 이미지 왜곡없이 스카이박스를 제작하는 방법을 간단히 소개합니다.

아마 앞으로 이런 방법이 사용되는 경우는 점차 없어지겠지만 그렇더라도 최소한의 리소스를 사용한 스카이박스가 필요한 경우가 있을겁니다. 그럴땐 이 방법을 사용해 보세요...^^*


1.맥스에 맵핑이 적용될 sphere 1개와 sphere의 중앙에 skybox가 적용될 작은 싸이즈의 box 하나를 생성시킵니다.


2. sphere에 edit mesh를 적용시킨 후 mesh를 flip시켜 맵핑이 적용될 환경을 안쪽으로 향하게 합니다.


3. sphere에 UVW Mapping을 적용시킨후 맵핑으로 사용할 하늘이미지를 불러와 Mapping을 적용시킵니다.


4 .두 번째 material 을 box에 지정해 준 후 box material의 self-illumination을 white로 낮춰주고 Opacity수치를 0으로 낮춰줍니다.


5. sphere의 중심에 omni light를 적당한 수치로 넣어 줍니다. 라이트를 넣는 이유는 sphere의 기본음영까지 렌더링될 텍스쳐에 적용이 되어버리기 때영될 이미지에 음영이 표현되지 않는 가장 사실적인 이미지를 얻기 위함입니다. 그렇기 때문에 sphere에 음영이 적용되지 않는 omni light가 가장 적당 합니다.


6. MAP의 Reflection에서 reflect/refract를 선택하여 줍니다.


7. reflect/refract parameters에서 from file을 체크해 주고 size에 렌더링될 이미지파일의 크기를 지정해 줍니다. 그리고 To file에서 이미지가 저장될 폴더를 지정해 준 후 오브젝트의 box를 선택해주면 지정된 폴더에 6개의 이미지가 렌더링 되는 것을 볼 수 있습니다.



8. 렌더링된 이미지를 만들고자 하는 월드의 skybox에 하나하나 죄표에 맞게 적용시키면 비교적 왜곡이 없는 skybox를 제작할 수 있습니다.


생각보다 간단한 방법으로 스카이박스 이미지를 제작할 수 있는 방법이지만 의외로 많이 사용되진 않는거 같더군요. 요즘게임에 있어서 폴리곤의 제약이 예전보다 점차 덜하기 때문에 sphere의 반구 형태로 제작해도 게임에 그다지 제약이 없긴하지만 가끔 스카이박스형태의 데이터 제작이 필요할 경우 이 방법을 사용해 보면 편할겁니다.

이상의 스카이박스 제작에 관한 듀토리얼은 G-Blender 게임엔진의 그래픽 메뉴얼에 사용된 듀토리얼의 일부이지만 엔진의 특성과는 관계없이 일반적으로 사용될수 있는 방법이기에 블로그에 공개합니다.대단한건 아니지만 기본적으로 저작권은 가이블에 있구요. 상업적인 무단사용은 불허합니다...^^* 그냥 참고로 봐주세요................................".내 영혼의 환타지 [김희선]"

출처 : http://blog.naver.com/cerulean9/20011965713
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2005/12/16 18:14 2005/12/16 18:14
, ,
Response
No Trackback , No Comment
RSS :
http://hansnara.pe.kr/blog/rss/response/10

Trackback URL : http://hansnara.pe.kr/blog/trackback/10

Leave a comment
[Login][OpenID?]

알파 블렌딩 (Alpha Blending)

1. 방법
각각의 용도가 다르며, 경우에 따라서 조합되어 사용될 수 있다.
a. Material Alpha - Mesh 단위
주로 전체적으로 Mesh에 Alpha를 줄 때 사용
멀리 있어서 투명하게 사라져야 할 때 또는 플레이어와 카메라 사이에 낀 오브젝트일 경우 등에 게임적으로 조절되는 알파값을 주어서 투명하게 만든다.
출력용 Alpha = 게임상에서 조절되는 Alpha * 원본 Material의 Alpha
-> 출력용 Material = 게임상에서 수정되는 Material * 원본 Material(보통 수정하지 않음)
(Material 값으로 알파 처리를 하려면 라이트를 켜야한다)
b. Texture Alpha - Pixel 단위
한 Mesh내에 Pixel별로 Alpha가 다를 때 사용
c. TFactor 이용
Texture Factor의 Alpha값으로 기존 텍스쳐와 modulate하여 투명도 변경
d. Vertex 정보의 Color값을 이용하여 투명도 조절


2. TGA 파일을 이용한 렌더링
나무, 꽃, 펜스를 그냥 렌더링 했을 경우

알파 테스트를 켜고 알파 블렌딩
풀이나 나무를 렌더링 할 때, 먼저 알파 테스트로 나뭇잎을 제외한 부분을 걸러내고, 나뭇잎의 경계선을 부드럽게 외부 세계와 섞어주기 위해서 알파 블렌드를 사용한다.
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x01);
g_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);

g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

나뭇잎,꽃,펜스와 같이 Plane으로 되어있는 오브젝트는 뒷면도 보여야하므로 back face culling을 하지 않음
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );


경계가 잘 빠지지 않는 문제는 D3DRS_ALPHAREF 값을 조절해줌으로 해결. (참조할 알파값을 넣어줘서 주어진 조건에 맞지 않는 알파 값이 들어간 픽셀을 렌더링에서 제외) D3DRS_ALPHAREF는 0x00000000 ~ 0x000000FF 사이의 값을 가질수있는데, 위의 상황에서는 이 값이 99 정도일때 가장 깔끔하게 렌더링 되었음. 이 값이 커지면 가장자리 부분이 많이 제거됨.
g_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, (DWORD)0x00000099 );


TGA파일과 같이 알파채널을 이용하는 경우 외에도 검정색을 컬러키로 사용(검정색을 빼고 렌더링)한다면 블랜딩 셋팅만 바꿔주는 것으로 동일한 효과를 볼 수 있다.
SRCBLEND -> ONE , DESTBLEND -> ONE

3. 소트
알파 블렌드에서는 먼저 그려진 픽셀의 알파와 혼합을 하기 때문에 렌더링 순서가 중요하다. (멀리있는 것 부터 렌더링해야 제대로 나온다) 가령, 월드를 렌더링하기 전에 잎사귀를 그리고 월드를 렌더링 한다면, 잎사귀는 백 버퍼를 클리어한 색깔과 혼합이 된다. 따라서 알파를 쓴 물체를 그릴때는 Depth Sort 를 해주는 것이 일반적이다. 멀리 있는 물체부터 앞으로 그리는 방식으로 나중에 Alpha 가 있는 물체 사이에 다른 물체를 그리지 않도록 하는 것이다. 정렬 기준은 카메라와의 거리이다.

투명한 객체(Alpha-Blending Object)들은 따로 모아서 불투명한 객체(Non-Alpha-Blending Object) 렌더링이 끝난 직후 정렬하여 렌더링한다. (Depth 없이 배경에 그릴 물체 -> 알파가 없는 물체 -> 알파가 있는 물체 -> Effect 로 모든 것 위에 올라갈 물체 -> Depth 맨위에 그릴 UI 의 순으로 렌더링)

그래도 생기는 문제가 폴리곤 단위 소팅 문제이다. 이는ALPHATEST(컬러키)를 켜주고 더해서 ALPHAREF 값을 조금 높게(0xc0 정도) 주면 폴리곤 소팅을 하지 않아도 무리없이 보인다. 디자이너는 싫어하지만 투명에 의해서 뒤가 뚫려 보이는 것 보다는 훨씬 낫다.

머리카락이나 무기 등과 같은 섬세하면서 클로즈업 되는 곳은 알파소팅 하여 렌더링하고 이펙트나 나뭇잎처럼 뒤범벅 되는 것은 대충 z-buffer 끄고 렌더링해도 무난하다.
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by hans

2005/12/15 18:09 2005/12/15 18:09
, ,
Response
2 Trackbacks , No Comment
RSS :
http://hansnara.pe.kr/blog/rss/response/9

Trackback URL : http://hansnara.pe.kr/blog/trackback/9

Trackbacks List

  1. Carisoprodol 350 mg able.

    Tracked from Carisoprodol. 2010/07/16 00:20 Delete

    Carisoprodol.

  2. Ambien.

    Tracked from Generic ambien. 2010/07/28 19:13 Delete

    What is ambien. Ambien cr. Ambien.

Leave a comment
[Login][OpenID?]