* 각 소스마다 주석으로 소스내 구조흐름과 노트정리를 해두었습니다.
* 튜토리얼 3부터는 자체적으로 변형한것들입니다.
C:\Program Files\Microsoft DirectX SDK (August 2009)\Documentation\DirectX9\directx_sdk.chm 을 실행해서 참고하는것도 좋습니다.
Tutorial 01: CreateDevice
더보기 접기
/*-----------------------------------------------------------------------------
// File: Tutorial 1.cpp
//-----------------------------------------------------------------------------*/
#include <d3d9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#pragma warning( default : 4996 )
// 윈도우 생성, 필수 라이브러리
//#pragma comment(lib, "user32.lib") // 윈도우 메시지, 기본함수등.
//#pragma comment(lib, "gdi32.lib") // 그래픽 관련.
//#pragma comment(lib, "kernel32.lib")// 프로세스 관련.
//DX관련 라이브러리
#pragma comment(lib, "d3dx9d.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "winmm.lib") //윈도우 타이머관련.
/*-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------*/
LPDIRECT3D9 g_pD3 = NULL; // Used to create the D3DDevice
//typedef struct IDirect3DDevice9 *LPDIRECT3DDEVICE9
// LPDIRECT3DDEVICE9 g_pd3dDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
float g_wnd_height = 300;
float g_wnd_width = 400;
/*-----------------------------------------------------------------------------
Name: InitD3D()
Desc: Initializes Direct3D
4개의 절차
1. DirectX Library의 설치 여부검사 및 장치 인터페이스 포인터 얻기
절차적으로 매우 간단한 과정
결과적으로 IDirect3D9 인터페이스의 포인터를 얻는다. 즉 Direct3D에 접근 가능한 포인터를 얻는 것이다.
2. D3DCAPS9을 통한 장치 성능 확인
일반 실습 과정에서는 생략 가능
현재 그래픽 카드가 구체적으로는 어떤 해상도와 필터 성능을 가지고 있는지를 미리 확인.
3. 화면 크기/동작 모드 등 설정
D3DPRESENT_PARAMETERS 구조체의 값 설정
4. D3DPRESENT_PARAMETERS를 통한 IDirect3DDevice9 객체 생성
//-----------------------------------------------------------------------------*/
HRESULT InitD3D( HWND hWnd )
{
/***********초기화 절차 : begin ***********/
//LPDIRECT3D9 g_pD3D = NULL;
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
//D3DPRESENT_PARAMETERS : 그래픽 카드설정 구조체
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp. Windowed = TRUE; //현재 윈도우 모드. FALSE는 전체화면
d3dpp. SwapEffect = D3DSWAPEFFECT_DISCARD; //그냥 되는데로 화면을 갱신한다
d3dpp. BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp. EnableAutoDepthStencil = FALSE; //No depth/stencil buffer
if( FAILED( g_pD3D->CreateDevice ( D3DADAPTER_DEFAULT, //사용할 그래픽 카드의 번호 지정
D3DDEVTYPE_HAL, //디바이스타입. HAL이나 REF
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&g_pd3dDevice ) ) )
{
return E_FAIL;
}
/***********초기화 절차 : end***********/
return S_OK;
}
/*-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------*/
VOID Cleanup()
{
/***********종료 절차 : begin. Release()가 중요. ***********/
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
/***********종료 절차 : end***********/
}
/*-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
용책에서는 display()
후면버퍼를 소거하고, 깊이/스텐실 버퍼를 설정가능
//-----------------------------------------------------------------------------*/
VOID Render()
{
int rgb_r = 50;
int rgb_g = 50;
int rgb_b = 50;
if( NULL == g_pd3dDevice )
return;
g_pd3dDevice->Clear( 0,
NULL, //표면의 특정영역만을 소거할수 있도록 해준다.
D3DCLEAR_TARGET, //랜더대상 표면(보통은 후면버퍼)
D3DCOLOR_XRGB( rgb_r, rgb_g, rgb_b ),
1.0f, //Z버퍼
0 //스텐실버퍼
);
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// Rendering of scene objects can happen here
// End the scene
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );//후면버퍼시연.
}
/*-----------------------------------------------------------------------------
Name: MsgProc()
//-----------------------------------------------------------------------------*/
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 );
}
/*-----------------------------------------------------------------------------
Name: wWinMain()
-> 프로그램 진입함수.
1. 초기화 : 메인 디스플레이 윈도우, Direct3D
2. 사전준비 : 어플리케이션 사전준비를 수행한다.
3. 메시지루프 : Render()함수를 이용해서 메시지루프에 진입
4. 정리 및 해제 :
//-----------------------------------------------------------------------------*/
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
//char wnd_title[] = "DX_3D 01 : 윈도우생성, 메시지 루프";
float wnd_height = g_wnd_height;
float wnd_width = g_wnd_width;
int wnd_x = 500;
int wnd_y = 300;
// Register the window class
WNDCLASSEX wc =
{
sizeof( WNDCLASSEX ),
CS_CLASSDC, MsgProc,
0L, 0L,
GetModuleHandle( NULL ), // 윈도우 필수함수: Instance 얻는 함수
NULL, NULL, NULL, NULL,
L"D3D Tutorial",
NULL
};
RegisterClassEx( &wc ); // 사용자가 설정한값을 wndclass 구조체 변수로 설정하고 등록.
// 윈도우 필수함수: CreateWindow()
HWND hWnd = CreateWindow( L"D3D Tutorial",
L"DX_3D 01 : 윈도우생성, 메시지 루프",
WS_OVERLAPPEDWINDOW,
wnd_x, wnd_y,
wnd_width, wnd_height,
NULL, NULL,
wc.hInstance, NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
MSG msg;
//기본 메시지루프: 일반 어플리케이션용.
// while( GetMessage( &msg, NULL, 0, 0 ) )
// {
// TranslateMessage( &msg );
// DispatchMessage( &msg );
// } // Ctrl+K+C && Ctrl+K+U
while( WM_QUIT != msg.message )
{
if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))// 윈도우 필수함수: 메세지큐에 메세지를 무조건 검사한다. 있다면 True값 리턴
{
GetMessage( &msg, NULL, 0, 0 ); // 메시지 큐에서 메시지를 읽음.
TranslateMessage( &msg ); // 키보드 입력에 대한 메시지 처리.
DispatchMessage( &msg ); // 메시지 큐에서 꺼낸 메시지를 WndProc로 전달.
}
//else
//{
// // 메세지가 없다면 게임루프를 돌린다.
//}
}
} // if( SUCCEEDED( InitD3D( hWnd ) ) )
UnregisterClass( L"D3D Tutorial", wc.hInstance );
return 0;
}
/* 윈도우 생성과정.
=> WndClass정의
=> RegisterClass() : 윈도우 클래스 등록
=> CreateWindow() : 메모리상에 윈도우 생성.
=> ShowWindow() : 윈도우를 화면에 표시.
=> 메시지 loop : 메시지를 처리.
//게임용(메시지)루프
while( WM_QUIT != msg.message )
=> GetMessage(), PeekMessage()
=> TranslateMessage()
=> DispatchMessage()
=> MessageProcedure()
*/
접기
버텍스 포맷 종류
->동명이형인 포맷중 택1
->위치, 색상, 텍스쳐좌표등
dwFVF = ( D3DFVF_XYZ | D3DFVF_DIFFUSE );
dwFVF = ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE );
dwFVF = ( D3DFVF_XYZ | D3DFVF_TEX2 );
dwFVF = ( D3DFVF_XYZRHW | D3DFVF_TEX2 );
dwFVF = ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE
| D3DFVF_SPECULAR | D3DFVF_TEX2 );
변환된 버텍스
->예. 성분 수동입력
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw;
//FLOAT x, y, z;
DWORD color; // DWORD로 색깔표현가능. 16진수 사용.
//RGB조합[0xargb]으로 각 원소는 0~255[256].
};
버텍스 포맷 세팅.
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE )
그리기 방법 인자
-> 멤버중 택1해서 사용.
typedef enum _D3DPRIMITIVETYPE
{
D3DPT_POINTLIST = 1,
D3DPT_LINELIST = 2, //독립된 라인들
D3DPT_LINESTRIP = 3, //연결된 라인들
D3DPT_TRIANGLELIST = 4, //독립된 삼각형들. 버텍스정보 기준으로 맞닿는 변이 없다.
D3DPT_TRIANGLESTRIP = 5,
D3DPT_TRIANGLEFAN = 6, //면을 폴리곤들의 집함으로 표현.
//오로지 하나의 버텍스가 공통점.
D3DPT_FORCE_DWORD = 0x7fffffff,
} D3DPRIMITIVETYPE;
정점들에 대한 입력.
버텍스 버퍼
-> 버퍼를 비디오 메모리에
저장 가능.
-> 배열보다 빠른 작업
D3DFVF_CUSTOMVERTEX,0,CUSTOMVERTEX Tutorial2[] =
{
{ 200.0f, 10.0f, 0.5f, 1.0f, 0xfff00000, }, // x→, y↓, z, rhw, color
{ 325.0f, 250.0f, 0.5f, 1.0f, 0x002ff200, },
{ 75.0f, 250.0f, 0.5f, 1.0f, 0x00002fff, }
// { 100.0f, 10.0f, 0.5f, 0xfff00000, }, // x→, y↓, z, rhw, color
// { 325.0f, 250.0f, 0.5f, 0x002ff200, },
// { 75.0f, 250.0f, 0.5f, 0x00002fff, }
};//삼각형 그리는 구조체.
//버텍스 버퍼만들기
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,//버퍼가 만들어지는 장소
&g_pVB,//버텍스 버퍼가 포인터에 저장
NULL // 언제나 NULL
)))
{
return E_FAIL;
}
VOID* pTutorial2;
//버텍스 구조체에 넣은 값을 버텍스 버퍼로 옮기기.
//메모리 주소를 얻어와서 집어넣음.
if( FAILED( g_pVB->Lock( 0, //잠금을 시작할 버퍼위치의 오프셋값
sizeof( Tutorial2 ), //잠글 바이트 수
( void** )&pTutorial2, //잠근 메모리의 포인터
0 //잠금이 이루어질 방법
) )) //버텍스 버퍼 메모리 포인터 획득.
return E_FAIL;
memcpy( pTutorial2, Tutorial2, sizeof( Tutorial2 ) );
//포인터에 버텍스 버퍼값 복사해 넣기
g_pVB->Unlock(); // 잠갔던 메모리 해제
SetStreamSource
-> 버텍스 버퍼를
N번 데이터 스트림에
연결.
DrawPrimitive
-> 버텍스 내용 그리는 함수
g_pd3dDevice->Clear( 0,
NULL, //표면의 특정영역만을 소거할수 있도록 해준다.
D3DCLEAR_TARGET, //랜더대상 표면(보통은 후면버퍼)
D3DCOLOR_XRGB( rgb_r, rgb_g, rgb_b ),
1.0f, //Z버퍼
0 //스텐실버퍼
);
// (Drawing)
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 //그려질 라인이나 삼각형등의 갯수.
);
// End the scene
g_pd3dDevice->EndScene(); //백버퍼에서의 랜더링 마무리.
}
//Device->Present
g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); //랜더링된 결과를 보임.
더보기 접기
//-----------------------------------------------------------------------------
// File: Tutorial2.cpp
//-----------------------------------------------------------------------------
#include <d3d9.h>
//#include <strsafe.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#pragma warning( default : 4996 )
// 윈도우 생성, 필수 라이브러리
#pragma comment(lib, "user32.lib") // 윈도우 메시지, 기본함수등.
#pragma comment(lib, "gdi32.lib") // 그래픽 관련.
#pragma comment(lib, "kernel32.lib")// 프로세스 관련.
//DX관련 라이브러리
#pragma comment(lib, "d3dx9d.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "winmm.lib") //윈도우 타이머관련.
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
float g_wnd_height = 300;
float g_wnd_width = 400;
// vertex(정점) type을 커스텀.
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw;
//FLOAT x, y, z;
DWORD color; // DWORD로 색깔표현가능. 16진수 사용.
// RGB조합[0xargb]으로 각 원소는 0~255[256]. (예. 0xffff0000 == 빨강색)
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
/*-----------------------------------------------------------------------------
Name: InitD3D()
Desc: Initializes Direct3D
//-----------------------------------------------------------------------------*/
HRESULT InitD3D( HWND hWnd )
{
//////////////////// Direct3D 초기화: 시작 ////////////////////
//LPDIRECT3D9 g_pD3D = NULL;//전역으로 이미 선언하면 여기서도 할 필요까진X
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
//Direct3D에 접근 가능한 포인터를 얻게됨.
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create the D3DDevice
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
// Device state would normally be set here
return S_OK;
//////////////////// Direct3D 초기화: 마무리 ////////////////////
}
//-----------------------------------------------------------------------------
// Name: InitVB()
//-----------------------------------------------------------------------------
HRESULT InitVB()
{
CUSTOMVERTEX Tutorial2[] =
{
{ 200.0f, 10.0f, 0.5f, 1.0f, 0xfff00000, }, // x→, y↓, z, rhw, color
{ 325.0f, 250.0f, 0.5f, 1.0f, 0x002ff200, },
{ 75.0f, 250.0f, 0.5f, 1.0f, 0x00002fff, }
// { 100.0f, 10.0f, 0.5f, 0xfff00000, }, // x→, y↓, z, rhw, color
// { 325.0f, 250.0f, 0.5f, 0x002ff200, },
// { 75.0f, 250.0f, 0.5f, 0x00002fff, }
};//삼각형 그리는 구조체.
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,//버퍼가 만들어지는 장소
&g_pVB,//버텍스 버퍼가 포인터에 저장
NULL // 언제나 NULL
) ) ) //버텍스 버퍼 메모리 포인터 획득.
{
return E_FAIL;
}
VOID* pTutorial2;
if( FAILED( g_pVB->Lock( 0, //잠금을 시작할 버퍼위치의 오프셋값
sizeof( Tutorial2 ), //잠글 바이트 수
( void** )&pTutorial2, //잠근 메모리의 포인터
0 //잠금이 이루어질 방법
) ) //포인터에 버텍스 버퍼값 복사해 넣기
return E_FAIL;
memcpy( pTutorial2, Tutorial2, sizeof( Tutorial2 ) );
//코드에서 lock. pTutorial2에 버퍼의 포인터를 얻어 옴.
g_pVB->Unlock(); // 잠갔던 메모리 해제
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
if( g_pVB != NULL )
g_pVB->Release();
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
}
/*-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
용책에서는 display()
후면버퍼를 소거하고, 깊이/스텐실 버퍼를 설정가능
Device->Clear // 먼저 화면을 지운다
(Drawing) // 그림을 그린다
Device->Present // 화면을 표시한다(Swap 방식에 의해서)
typedef enum _D3DPRIMITIVETYPE
{
D3DPT_POINTLIST = 1,
D3DPT_LINELIST = 2, //독립된 라인들
D3DPT_LINESTRIP = 3, //연결된 라인들
D3DPT_TRIANGLELIST = 4, //독립된 삼각형들. 버텍스정보 기준으로 맞닿는 변이 없다.
D3DPT_TRIANGLESTRIP = 5,
D3DPT_TRIANGLEFAN = 6, //면을 폴리곤들의 집함으로 표현.
//오로지 하나의 버텍스가 공통점.
D3DPT_FORCE_DWORD = 0x7fffffff,
} D3DPRIMITIVETYPE;
//-----------------------------------------------------------------------------*/
VOID Render()
{
int rgb_r = 50;
int rgb_g = 50;
int rgb_b = 50;
// Device->Clear
g_pd3dDevice->Clear( 0,
NULL, //표면의 특정영역만을 소거할수 있도록 해준다.
D3DCLEAR_TARGET, //랜더대상 표면(보통은 후면버퍼)
D3DCOLOR_XRGB( rgb_r, rgb_g, rgb_b ),
1.0f, //Z버퍼
0 //스텐실버퍼
);
// (Drawing)
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 //그려질 라인이나 삼각형등의 갯수.
);
// End the scene
g_pd3dDevice->EndScene();
}
//Device->Present
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
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 );
}
/*-----------------------------------------------------------------------------
// Name: wWinMain()
//-----------------------------------------------------------------------------*/
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
float wnd_height = g_wnd_height;
float wnd_width = g_wnd_width;
int wnd_x = 500;
int wnd_y = 300;
// Register the window class
WNDCLASSEX wc =
{
sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
L"D3D Tutorial", NULL
};
RegisterClassEx( &wc );
// 윈도우 필수함수: CreateWindow()
HWND hWnd = CreateWindow( L"D3D Tutorial",
L"DX_3D 02 : 삼각형 그리기",
WS_OVERLAPPEDWINDOW,
wnd_x, wnd_y,
wnd_width, wnd_height,
NULL, NULL,
wc.hInstance, NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Create the vertex buffer
if( SUCCEEDED( InitVB() ) )
{
// Show the window
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;
}
접기
-> 현재 포스팅한 소스는 기존 예제에서 버텍스버퍼를 활용한 2개의 매트릭스를 월드변환한 좌표에 넣었다.
-> D3DX 라이브러리에서 제공하는 기본매쉬중 육면체를 추가해서 그려넣었다.
(참고1 : 용책 3장.)
(참고2 : DirectX를 이용한 3차원 그래픽 프로그래밍 기초 )
(참고 : 게임코디, 월드변환에 대해. )
더보기 접기
/*-----------------------------------------------------------------------------
// File: Tutorial3.cpp
1. 버텍스/인덱스버퍼를 만든다.[객체생성 함수 Create류 사용]
g_pDevice->CreateVertexBuffer() : 버텍스버퍼, 순수하게 정점들의 위치만
g_pDevice->CreateIndexBuffer() : 정점들을 사용하는 기본삼각형들의 정보.
2. 버퍼메모리 접근
g_pVB->lock()
g_pVB->unlock()
3. 랜더링 설정.
g_pDevice->SetRenderState()
4. 드로잉 준비.
g_pDevice->SetStreamSource() : 버텍스버퍼와 연결하여 버퍼의 기하정보를 파이프라인에 전달.
g_pDevice->SetFVF() : 버텍스포맷 지정. 이후의 드로잉 호출에 이용될 버텍스포맷 지정.
g_pDevice->SetIndices() : 인덱스버퍼 지정.
5. 장면의 시작, 후면버퍼 랜더링함수(Draw류), 장면의 끝
g_pDevice->BeginScene()
g_pDevice->DrawPrimitive( ..., 기본삼각형_갯수 ) : 인덱스버퍼 지정.
g_pDevice->DrawIndexedPrimitive() : 인덱스정보로 기본형그리기.
g_pDevice->EndScene()
* 기본매쉬그리기
-> 참고로 메쉬는 그려줄때마다 월드메트릭스 지정.
①헤더 : d3dx9shape.h
②매쉬 포인터 변수 : ID3DXMesh *pMesh = 0
③매쉬 생성
D3DXCreateTeapot(g_pDevice, &pMesh, NULL)
D3DXCreateBox(...)
D3DXCreateSphere() 등등.
④매쉬 그리기
pMesh->DrawSubset(0)
⑤해제 : pMesh->Release()
pMesh = 0
//-----------------------------------------------------------------------------*/
#include <Windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9shape.h>//기본매쉬사용: ①헤더
#pragma warning( disable : 4996 )
#pragma warning( default : 4996 )
// 윈도우 생성, 필수 라이브러리
//#pragma comment(lib, "user32.lib") // 윈도우 메시지, 기본함수등.
//#pragma comment(lib, "gdi32.lib") // 그래픽 관련.
//#pragma comment(lib, "kernel32.lib")// 프로세스 관련.
//DX관련 라이브러리
#pragma comment(lib, "d3dx9d.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "winmm.lib") //윈도우 타이머관련.
/*-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------*/
LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
ID3DXMesh *pMesh = 0;//기본매쉬사용: ② 매쉬를 담을 변수선언
float g_wnd_height = 400;
float g_wnd_width = 500;
// A structure for our custom vertex type
struct CUSTOMVERTEX
{
FLOAT x, y, z; // (튜토리얼02 처럼) rhw가 있으면 좌표이동이나 회전이 안 되는걸로 알고 있음.
DWORD color; // The vertex color
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
/*-----------------------------------------------------------------------------
Name: InitD3D()
Desc: Initializes Direct3D
4개의 절차
1. DirectX Library의 설치 여부검사 및 장치 인터페이스 포인터 얻기
절차적으로 매우 간단한 과정
결과적으로 IDirect3D9 인터페이스의 포인터를 얻는다. 즉 Direct3D에 접근 가능한 포인터를 얻는 것이다.
2. D3DCAPS9을 통한 장치 성능 확인
일반 실습 과정에서는 생략 가능
현재 그래픽 카드가 구체적으로는 어떤 해상도와 필터 성능을 가지고 있는지를 미리 확인.
3. 화면 크기/동작 모드 등 설정
D3DPRESENT_PARAMETERS 구조체의 값 설정
4. D3DPRESENT_PARAMETERS를 통한 IDirect3DDevice9 객체 생성
//-----------------------------------------------------------------------------*/
HRESULT InitD3D( HWND hWnd )
{
/***********초기화 절차 : begin ***********/
//LPDIRECT3D9 g_pD3D = NULL;
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
//D3DPRESENT_PARAMETERS : 그래픽 카드설정 구조체
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create the D3DDevice
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pDevice ) ) )
{
return E_FAIL;
}
/***********초기화 절차 : end***********/
// Turn off culling, so we see the front and back of the triangle
g_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Turn off D3D lighting, since we are providing our own vertex colors
g_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
return S_OK;
}
/*-----------------------------------------------------------------------------
// Name: InitGeometry()
로컬스페이스로 버텍스행렬을 구현.
이 버텍스행렬을 버텍스버퍼에 보관.
버텍스버퍼메모리에 접근해서 저장.
//-----------------------------------------------------------------------------*/
HRESULT InitGeometry()
{
//로컬좌표로 표현된 버텍스행렬
CUSTOMVERTEX g_Vertices[] =
{
{ -1.0f,-1.0f, 0.0f, 0xffff0000, },//v0
{ 1.0f,-1.0f, 0.0f, 0xff0000ff, }, //v1
{ 0.0f, 1.0f, 0.0f, 0xffffffff, }, //v2
};
// Create the vertex buffer.
if( FAILED( g_pDevice->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ),//버텍스 N개 보관가능한 버텍스버퍼 생성.
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pVB,
NULL ) ) )
{
return E_FAIL;
}
// vertex buffer메모리에 접근하기
VOID* pVertices;
if( FAILED( g_pVB->Lock( 0, sizeof( g_Vertices ), ( void** )&pVertices, 0 ) ) )//lock()함수로 전체 버퍼를 잠금.
return E_FAIL;
memcpy( pVertices, g_Vertices, sizeof( g_Vertices ) );//버퍼에 버텍스정보 저장.
g_pVB->Unlock();//버퍼의 잠금해제
return S_OK;
}
/*-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------*/
VOID Cleanup()
{
if( g_pVB != NULL )
g_pVB->Release();
if( g_pDevice != NULL )
g_pDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
//기본매쉬사용: ⑤해제
if( pMesh != NULL )
{
pMesh->Release();
pMesh = 0;
}
}
/*-----------------------------------------------------------------------------
// Name: SetupTutorial_3()
// D3DXMATRIXA16로 물체(mat), 카메라, 투영, 월드좌표 지정가능.
//-----------------------------------------------------------------------------*/
VOID SetupTutorial_3()
{
UINT iTime = timeGetTime() % 1000;
FLOAT fAngle = iTime * ( 1.0f * D3DX_PI ) / 1000.0f;
//삼각형1
D3DXMATRIXA16 tri1;
D3DXMatrixRotationY( &tri1, fAngle );
D3DXMatrixTranslation(&tri1, -1.5, 0, 0);
g_pDevice->SetTransform( D3DTS_WORLD, &tri1 );//정점변환. Translation로 지정한 월드좌표로
g_pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT);
g_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );
//삼각형2
D3DXMATRIXA16 tri2;
D3DXMatrixTranslation(&tri2, 1.5, 0, 0);
g_pDevice->SetTransform( D3DTS_WORLD, &tri2 );//정점변환. Translation로 지정한 월드좌표로
g_pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
g_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );
//매쉬: 상자
D3DXMATRIXA16 matMesh;
D3DXMatrixTranslation(&matMesh, 0, 0, 5);
D3DXCreateBox(g_pDevice, 2, 2, 2, &pMesh, NULL);//기본매쉬사용: ③매쉬 생성
g_pDevice->SetTransform( D3DTS_WORLD, &matMesh );
pMesh->DrawSubset(0); //기본매쉬사용: ④매쉬 그리기
//카메라
D3DXVECTOR3 vEyePt( 0.0f, 2.0f,-6.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView; //SetTransform에도 들어가는 변환타입?
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pDevice->SetTransform( D3DTS_VIEW, &matView );//D3DTS_VIEW 카메라 위치, 딱1개
//투영변환
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
g_pDevice->SetTransform( D3DTS_PROJECTION, &matProj );//D3DTS_PROJECTION 사물이 멀수록 좁아지도록함, 딱1개
//D3DTS_WORLD 물체의 위치, 사물마다 1개씩, 그리기전에 각각설정
//D3DTS_VIEW 카메라의 위치, 딱1개
//D3DTS_PROJECTION 투영방법, 사물이 멀수록 좁아지도록함, 딱1개
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
int rgb_r = 50;
int rgb_g = 50;
int rgb_b = 50;
// Device->Clear
g_pDevice->Clear( 0,
NULL, //표면의 특정영역만을 소거할수 있도록 해준다.
D3DCLEAR_TARGET, //랜더대상 표면(보통은 후면버퍼)
D3DCOLOR_XRGB( rgb_r, rgb_g, rgb_b ),
1.0f, //Z버퍼
0 //스텐실버퍼
);
// (Drawing)
if( SUCCEEDED( g_pDevice->BeginScene() ) )
{
SetupTutorial_3();
// Render the vertex buffer contents
g_pDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
g_pDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
//g_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );
// End the scene
g_pDevice->EndScene();
}
//Device->Present
g_pDevice->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
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 );
}
/*-----------------------------------------------------------------------------
// Name: WinMain()
//-----------------------------------------------------------------------------*/
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
float wnd_height = g_wnd_height;
float wnd_width = g_wnd_width;
int wnd_x = 500;
int wnd_y = 300;
// 윈도우 생성-①WndClass정의
WNDCLASSEX wc =
{
sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
L"D3D Tutorial", NULL
};
// 윈도우 생성-②RegisterClass() : 윈도우 클래스 등록
RegisterClassEx( &wc );
// 윈도우 생성-③CreateWindow() : 메모리상에 윈도우 생성.
HWND hWnd = CreateWindow( L"D3D Tutorial",
L"D3D Tutorial 03: Tutorial_3",
WS_OVERLAPPEDWINDOW,
wnd_x, wnd_y,
wnd_width, wnd_height,
NULL, NULL,
wc.hInstance,
NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Create the scene geometry
if( SUCCEEDED( InitGeometry() ) )
{
// 윈도우 생성-④ShowWindow() : 윈도우를 화면에 표시.
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// 윈도우 생성-⑤메시지 loop : 메시지를 처리.
MSG msg;
ZeroMemory( &msg, sizeof( msg ) );
while( msg.message != WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg ); // 키보드 입력에 대한 메시지 처리.
DispatchMessage( &msg ); // 메시지 큐에서 꺼낸 메시지를 WndProc로 전달.
}
else
Render();
}
}
}
UnregisterClass( L"D3D Tutorial", wc.hInstance );
return 0;
}
접기
조명.
Diffuse : 난반사광의 양 조절.
Ambient : 환경광의 양 조절.
Specular : 정반사광의 양 조절.
Emissive : 전반적인 표면의 컬러. 물체 자체의 색상지정.
Power : 정반사광 강도 조절. 높은 값일수록 하이라이트 강조.
typedef struct _D3DLIGHT9
{
D3DLIGHTTYPE Type;
D3DCOLORVALUE Diffuse; /* Diffuse color of light */
D3DCOLORVALUE Specular; /* Specular color of light */
D3DCOLORVALUE Ambient; /* Ambient color of light */
D3DVECTOR Position; /* Position in world space */
D3DVECTOR Direction; /* Direction in world space */
float Range;
float Falloff;
float Attenuation0; /* Constant attenuation */
float Attenuation1; /* Linear attenuation */
float Attenuation2; /* Quadratic attenuation */
float Theta; /* Inner angle of spotlight cone */
float Phi; /* Outer angle of spotlight cone */
} D3DLIGHT9;
광원.
① 점 광원(point light): 월드 스페이스내 존재. 광원에서 모든방향으로 빛을 방산.
-> 위치값O, 방향성X [백열전구]
-> Position, Range, Attenuation
② 방향성 광원(directional light): 빛의 진행방향으로 평행하게 발산.
-> 특정한 색상. 위치값X. 방향성O [태양]
-> Direction,
③ 스포트 광원(spot light): 무대의 조명이나 손전등처럼 빛이 월뿔형으로 발산. 광원의 법선에 근접할수로 밝음.
-> 특정한 색상. 위치값O, 방향성O
-> Position, Direction, Range, Falloff(보통 1.0), Attenuation, Theta(원뿔의 내부각쯤?), Phi
표면, 면 법선(face normal )
표면, 버텍스 법선(vertex normal)
[ 이미지 출처, 바로가기 ]