본문 바로가기

DX

삼각형 그리기..

728x90
반응형

안녕하세요 엔젤루스입니다 ^^

오늘은 DirectX sdk를 이용하여 간단한 삼각형을 그리는 프로그램을 만들어 보겠습니다.

오늘도 이전 포스팅과 거의 비슷한 코드를 가지고 있습니다.

그럼 한번 진행해 보도록 하겠습니다.

Direct3D로 생성 된 어플리케이션은 정점을 사용해서 지오메트리 형상을 drawing 합니다. 3차원 Scene에서는 이러한 지오메트리 형상이 1개 이상을 포함하게 되는 것입니다. 이번에는 위에서 말한것 같이 간단한 삼각형을 그려보도록 하겠습니다.

3개의 정점을 사용해서 2D의 삼각형을 랜더링 하는데요. 정점의 저장 및 렌더링을 하기 위해서 Direct3D 개체인 정점 버퍼의 개념을 사용하고 있습니다.

struct CUSTOMVERTEX

{

  FLOAT x, y, z, rhw;

  DWORD color;

};
위 코드와 같이 구조체를 이용하여 커스텀 정점 타입의 포맷을 지정하게 됩니다. 그리고 위 구조체의 정점 타입에 대응하는 FVF를 정의 해줘야 합니다.

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
D3DFVF는 사용하는 커스텀 정점의 타입을 지정하게 됩니다. 즉 커스텀 정점 타입이 변환 된 정점과 색성분을 가지는 정점 버퍼에 통지를 하게 되는 것이죠.

그런다음은 정점을 초기화 시키는 작업을 하게 됩니다. 여기서는 어플리케이션을 초기화 하는 함수인 InitVB를 호출하게 되고 정점을 초기화시키죠.

CUSTOMVERTEX vertices[] =

  {

    {150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000,},

    {250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },

    {50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },

  };

위 코드는 삼각형의 3개의 정점을 설정하고 각 정점에서 색이 다른 색을 뿌려주게 설정해 놓은것입니다. 이 때 주의 할 점이라면 정점의 순서가 정확해야 제대로 된 삼각형을 볼수가 있습니다. 위, 왼쪽이 먼저 찍혀야 되고 아래, 오른쪽으로 갈수록 나중에 나와야 된다는 것이죠.

if(FAILED(g_pd3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL)))

  {

    return E_FAIL;

  }

 

  VOID* pVertices;

  if(FAILED(g_pVB->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))

    return E_FAIL;

  memcpy(pVertices, vertices, sizeof(vertices));

  g_pVB->Unlock();


그 다음은 CreateVertexBuffer를 호출해 정점 버퍼를 생성합니다. 이녀석의 최초 두개의 인수는 새로운 정점 버퍼의 사이즈와, 사용방법을 Direct3D에 통지합니다. 그다음은 버퍼의 벡터 포맷과 메모리 영역을 지정하고 마지막 인수는 정점 버퍼의 주소를 알려주게 되는 것이죠. 그리고 Lock를 호출하여 버퍼를 잠금처리후 정점을 버퍼에 저장하고 다시 Unlock으로 잠금을 풀어주게 되는 것입니다.

버퍼에 저장을 하고 나서 이제 그것을 표시해줘야 하는데요. 그 처리는 Render()함수에서 처리해 주게 됩니다. Scene를 시작하고 나면 3개의 과정을 가지면서 디스플레이 해주게 됩니다.

    g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));

    g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

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

우선 SetStreamSource를 이용해 스트림 소스를 정점 버퍼에 바인딩 시켜주게 되죠.. 그리고 SetFVF를 호출해 정점 셰이더를 설정해 줍니다.. 이때 SetFVF는 정점 데이터 레이아웃을 정의하는 기능을 하게 되는 것이죠.. 마지막으로 정점 버퍼에서 디스플레이 해주게 되는데 DrawPrimitive를 사용하게 됩니다.

전체적인 소스를 보면 다음과 같습니다.

#include <d3d9.h>

 

LRESULT WINAPI MsgProc(HWND, UINT, WPARAM, LPARAM);

HRESULT InitD3D(HWND hWnd);

HRESULT InitVB();

VOID Cleanup();

VOID Render();

 

struct CUSTOMVERTEX

{

  FLOAT x, y, z, rhw;

  DWORD color;

};

 

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

 

LPDIRECT3D9 g_pD3D = NULL;

LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;

LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;

 

INT WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)

{

  WNDCLASSEX wc=

  {

    sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"D3D Tutorial", NULL

  };

  RegisterClassEx(&wc);

 

  HWND hWnd = CreateWindow(L"D3D Tutorial", L"D3D Tutorial 02:Vertices",  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, wc.hInstance, NULL);

 

  if(SUCCEEDED(InitD3D(hWnd)))

  {

    if(SUCCEEDED(InitVB()))

    {

      ShowWindow(hWnd, SW_SHOWDEFAULT);

      UpdateWindow(hWnd);

 

      MSG msg;

      ZeroMemory(&msg, sizeof(msg));

      while(msg.message!=WM_QUIT)

      {

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

        {

          TranslateMessage(&msg);

          DispatchMessage(&msg);

        }

        else

        {

          Render();

        }

      }

    }

  }

  UnregisterClass(L"D3D Tutorial", wc.hInstance);

  return 0;

}

 

LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

  switch(msg)

  {

  case WM_DESTROY:

    Cleanup();

    PostQuitMessage(0);

    return 0;

  }

  return DefWindowProc(hWnd, msg, 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.BackBufferCount =D3DFMT_UNKNOWN;

 

  if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &g_pd3dDevice)))

  {

    return E_FAIL;

  }

  return S_OK;

}

 

HRESULT InitVB()

{

  CUSTOMVERTEX vertices[] =

  {

    {150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000,},

    {250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },

    {50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },

  };

 

  if(FAILED(g_pd3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL)))

  {

    return E_FAIL;

  }

 

  VOID* pVertices;

  if(FAILED(g_pVB->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))

    return E_FAIL;

  memcpy(pVertices, vertices, sizeof(vertices));

  g_pVB->Unlock();

  return S_OK;

}

 

VOID Cleanup()

{

  if(g_pVB != NULL)

  {

    g_pVB->Release();

  }

  if(g_pd3dDevice != NULL)

  {

    g_pd3dDevice->Release();

  }

  if(g_pD3D != NULL)

  {

    g_pD3D->Release();

  }

}

 

VOID Render()

{

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

 

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

  {

    g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));

    g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

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

 

    g_pd3dDevice->EndScene();

  }

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

}


결과는 아래와 같이 색깔이 들어 있는 이쁜 삼각형이 출력이 됩니다.


간단히 프로그램을 바꿔 삼각형을 역 삼각형으로 만들어 보자면 다음과 같은 수정만 하면 가능하게 됩니다.

CUSTOMVERTEX vertices[] =

  {

    {50.0f, 50.0f, 0.5f, 1.0f, 0xff00ffff, },

    {250.0f, 50.0f, 0.5f, 1.0f, 0xff00ff00, },

    {150.0f, 250.0f, 0.5f, 1.0f, 0xffff0000,},

  };

이렇게만 수정해 주시면 역삼각형의 모습을 볼 수 있을 것입니다~~

한번 확인해 보시고 여러 모양의 삼각형을 한번 만들어 보시도록 하세요 ^^

오늘도 참 허접하게 글을 쓴거 같네요 ㅜ_ㅜ

날씨도 점점 더워지고 힘들어지는데요...그래도 열심히 해보도록 하겠습니다~~

지금까지 엔젤루스였습니다 ^^

감사합니다~

728x90
반응형

'DX' 카테고리의 다른 글

DirectX 첫 시작 - 장치의 생성.  (0) 2010.05.09